MST

星途 面试题库

面试题:C++类成员访问属性:复杂场景下的访问控制与设计模式

假设你正在设计一个大型的游戏引擎框架,其中有多个层次的类继承关系和复杂的模块交互。在这个场景下,如何利用C++的类成员访问属性(包括public、private、protected以及友元机制)来实现模块间的安全交互、数据隐藏和合理的接口暴露,同时结合某种设计模式(如单例模式、策略模式等)进行说明。请详细阐述设计思路并给出关键代码片段。
10.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计思路

  1. 数据隐藏与访问控制
    • 使用private成员来隐藏关键的数据和实现细节,防止外部模块直接访问。例如,游戏引擎中的渲染模块可能有一些与图形硬件交互的内部数据结构,这些应该设为private
    • 使用public成员函数作为接口,暴露给其他模块调用。比如,渲染模块对外提供的DrawScene()函数,用于绘制整个场景。
    • protected成员可用于继承体系中,子类可以访问这些成员,而外部模块不能访问。如在一个通用的游戏对象基类GameObject中,一些与对象初始化相关的成员设为protected,以便子类在初始化时使用。
  2. 友元机制:当需要在不公开private成员的情况下,允许特定的类或函数访问这些成员时,使用友元机制。例如,游戏的资源管理模块可能需要直接访问渲染模块的一些private资源加载函数,这时可以将资源管理模块的相关类设为渲染模块类的友元。
  3. 结合设计模式
    • 单例模式:在游戏引擎中,很多模块可能只需要一个实例,如资源管理器、输入管理器等。单例模式可以确保这些模块全局唯一。例如,资源管理器负责加载和管理游戏中的所有资源,使用单例模式可以避免多个资源管理器实例导致的资源重复加载和管理混乱。
    • 策略模式:游戏中的不同行为,如角色的移动行为(跑步、跳跃、飞行等),可以使用策略模式实现。将这些行为封装成不同的策略类,通过组合方式在需要时替换行为,而不是在一个类中使用大量的条件语句。

关键代码片段

单例模式示例(以资源管理器为例)

class ResourceManager {
private:
    static ResourceManager* instance;
    // 资源管理相关的private数据
    std::map<std::string, std::shared_ptr<Resource>> resources;
    ResourceManager() {}
    ~ResourceManager() {}
    // 禁止拷贝构造和赋值
    ResourceManager(const ResourceManager&) = delete;
    ResourceManager& operator=(const ResourceManager&) = delete;
public:
    static ResourceManager* getInstance() {
        if (instance == nullptr) {
            instance = new ResourceManager();
        }
        return instance;
    }
    // 公开的资源加载接口
    std::shared_ptr<Resource> loadResource(const std::string& name) {
        // 加载资源的逻辑
        auto it = resources.find(name);
        if (it != resources.end()) {
            return it->second;
        }
        // 加载新资源并添加到资源表
        std::shared_ptr<Resource> newResource = std::make_shared<Resource>(name);
        resources[name] = newResource;
        return newResource;
    }
};
ResourceManager* ResourceManager::instance = nullptr;

策略模式示例(以角色移动行为为例)

// 移动策略基类
class MovementStrategy {
public:
    virtual void move() = 0;
};

// 跑步策略类
class RunStrategy : public MovementStrategy {
public:
    void move() override {
        std::cout << "Character is running." << std::endl;
    }
};

// 跳跃策略类
class JumpStrategy : public MovementStrategy {
public:
    void move() override {
        std::cout << "Character is jumping." << std::endl;
    }
};

// 角色类,使用策略模式
class Character {
private:
    std::unique_ptr<MovementStrategy> movementStrategy;
public:
    Character() {
        movementStrategy = std::make_unique<RunStrategy>();
    }
    void setMovementStrategy(std::unique_ptr<MovementStrategy> newStrategy) {
        movementStrategy = std::move(newStrategy);
    }
    void performMovement() {
        movementStrategy->move();
    }
};

类成员访问控制示例(以简单的渲染模块为例)

class Renderer {
private:
    // 与图形硬件交互的private数据
    GraphicsDevice* device;
    // 初始化图形设备的private函数
    void initializeDevice() {
        device = new GraphicsDevice();
        // 初始化设备的逻辑
    }
protected:
    // 一些可被子类访问的渲染辅助函数
    void setupRenderState() {
        // 设置渲染状态的逻辑
    }
public:
    Renderer() {
        initializeDevice();
    }
    ~Renderer() {
        delete device;
    }
    // 公开的绘制场景接口
    void DrawScene() {
        setupRenderState();
        // 绘制场景的逻辑
    }
};

// 资源管理类,作为Renderer的友元
class ResourceManager {
public:
    void loadRenderResources(Renderer& renderer) {
        // 这里可以访问Renderer的private成员,如device
        // 加载渲染资源的逻辑
    }
};
// 将ResourceManager设为Renderer的友元
friend class ResourceManager;