自从我加入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成员的替代方法在程序的其余运行时间内运行。
感谢您的帮助。
答案 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对象,并返回对它的引用。