C ++ Only允许成员变量设置一次

时间:2013-06-04 20:54:56

标签: c++ const mutable const-correctness

自从我加入C ++以来已经有一段时间了,但我想确保我坚持使用最佳实践,包括保持正确。

我目前正在为游戏框架构建一个代码库,我有以下类(为简单起见而总结):

class Screen
{
public:
    Clear();
}

class Game
{
private:
    Screen* screen;

protected:
    const Screen* GetScreen() const;
}

为简洁起见,我省略了其余部分,但足以说明,Game类负责创建Screen类实例。创建后,只能通过GetScreen()方法访问它。

这个想法是,在创建一个新游戏时,我会继承这个基类,所以作为一个例子,在渲染循环中我想清除屏幕重绘下一帧。现在,在我的上述定义中,使用Clear()方法时不允许调用GetScreen()方法,因为它不是const。 clear方法实际上会改变类的内部工作方式(由于先前显示的图像被清除的事实),这就是我将const声明从定义中删除的原因。如果我做了const那么我必须将Screen类的一些内部工作方式作为mutable,但从我读过的内容来看,这将不是非常正确的

所以,我的问题分为两部分。我应该将void Clear()更改为void Clear() const并制作部分内部工作原因mutable吗?

或者是允许我使screen类的Game成员只能由Game类设置一次以便我可以访问非const成员的替代方法在程序的其余运行时间内运行。

感谢您的帮助。

3 个答案:

答案 0 :(得分:0)

由于Game::screen是私有的,因此派生类无法访问它。虽然GetScreen()的来电者可以访问Screen对象,但他无法修改Game存储的screen所指向的内容。所以你完全没问题,例如提供这两个重载:

class Game
{
  Screen *screen;

protected:
  const Screen* GetScreen() const;
  Screen* GetScreen();
};

它们都不允许派生类修改screen指针本身,因此它无法“重置”它指向Game不希望它指向的地方。

答案 1 :(得分:0)

'const'的概念对于指示对象的内部状态不应该是可修改的有用。

void f(const Object& o)
{
    // 'o' cannot be modified
}

将非静态成员标记为const的功能允许您强制对该对象的const引用的持有者不能修改内部状态。例如,在以下场景中,Object有一个访问者str,它返回对内部状态的引用,该状态具有非const和const重载:

struct Object
{
    // non-const: caller can modify internal state
    std::string& str();

    // const: caller cannot modify internal state
    const std::string& str() const;
};

非const重载允许修改内部状态,但只能在对象的非const引用上调用; const重载不允许修改内部状态,并且可以与const和非const对象引用一起使用。

在您提供的方案中,Game似乎是一个整体singleton对象,其中包含程序中的所有内容。如果是这样,那么将Game - 或者从它派生的对象 - 的引用传递出来是有用的 - 使const Game&Game&之间的区别有点没有用。如果是这种情况,const-correctness没有实用性,如果你只是让Game的所有成员都成为非const,你就会为自己省事。

答案 2 :(得分:-1)

我强烈建议您更新您对C ++指针的了解。这几天几乎没有理由使用原始指针。

要直接回答这个问题,Game.GetScreen()函数会想要'const',具体取决于你对它的行为的准确程度。

如果返回const Screen*,则返回指向常量(不能修改)的Screen对象的指针。你通常希望制作一个这样的函数const,允许它在一个自己的游戏对象上调用。如果有人拥有非const游戏对象,你可以允许他们获取Screen对象,然后只需返回Screen*即可修改它们。

那就是说,我回到开头,不应该使用原始指针。

最初,你应该按照值存储Screen对象,并返回引用,为你提供一个类:

Class Game{
    Screen screen;
public:
    const Screen& GetScreen() const{ return screen; }
    Screen& GetScreen(){ return screen; }
};

这可能看起来像是在复制Screen对象以返回它,但返回类型确保您返回对同一屏幕对象的引用,而不是副本。

如果您确实需要动态创建Screen对象(即,您无法在创建Game对象之前或创建Game对象时创建它),那么您应该使用std::unique_ptr<Screen>。这可以像原始指针一样使用,但会为您处理很多功能。但是,您希望共享对此Screen指针的访问权限,因此您可能希望使用std::shared_ptr<Screen>并从get函数返回std::weak_ptr<Screen>。 weak_ptr可用于允许其他人访问,但您的初始Game对象仍然拥有 Screen对象。

长话短说,按值存储Screen对象,并返回对它的引用。