3

It's been a while since I've jumped into C++ but I want to make sure I'm sticking to best practices when I do, including being const-correct.

I'm currently building a library of code for a game framework and I have the following classes (summarised for simplicity):

class Screen
{
public:
    Clear();
}

and

class Game
{
private:
    Screen* screen;

protected:
    const Screen* GetScreen() const;
}

I've omitted the rest for brevity but suffice it to say, the Game class is responsible for the creation of the Screen class instance. After it is created, it should only be accessed through the GetScreen() method.

The idea is, that when creating a new game, I would inherit from this base class, so as an example, during a render loop I would want to clear the screen to redraw the next frame. Now, in my above definitions, the Clear() method is not allowed to be called when using the GetScreen() method because it is not const. The clear method would actually change the internal workings of the class (by virtue of the fact that the previously displayed image is cleared) so that is why I left the const declaration out of the definition. If I made it const then I would have to have some of the inner workings of the Screen class as mutable but from what I've read, this would not be very const-correct.

So, I have two parts to my question. Should I change void Clear() to void Clear() const and make parts of the inner workings mutable?

Or is the an alternative that would allow me to make the screen member of the Game class only settable once by the Game class so that I can access the non-const member functions during the rest of the program's run time.

Thanks for any help.

4

3 回答 3

1

由于Game::screen是私有的,派生类不能访问它。虽然 的调用者GetScreen()可以访问该Screen对象,但他不能修改Game' 的存储screen指向的内容。所以你完全可以提供这两个重载:

class Game
{
  Screen *screen;

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

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

于 2013-06-04T21:13:49.030 回答
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 对象引用一起使用。

在您呈现的场景中,它Game似乎是一个包含程序中所有内容的整体单例对象。Game如果是这样,那么将引用传递给一个或从它派生的对象const Game&是有用的,这似乎是有问题的Game&Game如果是这种情况,则 const-correctness 没有用处,如果您简单地将所有成员都设为非 const ,您将不会感到头疼。

于 2013-06-04T21:48:55.890 回答
-1

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

要直接回答这个问题,该Game.GetScreen()函数会根据您希望它的行为方式不同地“const”。

如果您返回 aconst Screen*您将返回一个指向不变(无法修改)的 Screen 对象的指针。您通常希望使这样的函数 const 允许在自身为 const it 的 Game 对象上调用它。如果某人有一个非常量的 Game 对象,您可以允许他们获取 Screen 对象,然后他们可以通过简单地返回 a 来修改该对象Screen*

也就是说,我回到我的开场白,你不应该使用原始指针。

最初,您应该只将 Screen 对象按值存储,并返回引用,从而为您提供一个类:

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

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

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

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

于 2013-06-26T18:28:56.573 回答