class SomeClass {
public:
void Render() const;
private:
mutable Cache m_some_cache;
};
上面的类是否正确?我何时可以安全地说“此操作不会更改实例的内部状态”?
在上面的示例中,SomeClass是在屏幕上呈现内容的东西。它使用缓存(例如OpenGL缓冲区对象)来允许更快地处理进一步的调用。所以内部改变的唯一事情就是缓存对象。我问自己缓存是否已经属于渲染器的内部状态。
这个例子很小,但是在我的实际应用程序中,这是一个有很多类的道路,即涉及很多Render()调用,而且大多数只进行缓存。但是有些人还通过资源加载器加载资源 - 这里的假设是正确的,即使查询资源管理器加载资源,方法也可能是const吗?
答案 0 :(得分:6)
当我们说“内部状态不会改变”时,我们指的是纯粹的 逻辑 事物。 逻辑 决定是否更改m_some_cache
会更改对象状态。正确性是 逻辑 问题。因此,如果您认为从用户的角度来看,更改m_some_cache
不会影响对象状态(在 逻辑 意义上),则代码为const -correct。
在您的特定情况下,我认为没关系。
答案 1 :(得分:4)
这样想。这完全有效:
void Type::print_self () const {
std::cout << *this << std::endl;
}
您不是在修改对象本身,因此使用const
限定符是完全有效的。此方法正在修改std::cout
,但这不会计入const
的{{1}}范围。
尽管如此,Type::print_self()
在我看来是矛盾的,除非你只在mutable Cache
内使用Cache
元素进行本地存储。如果您真的将它用作缓存,那么将此元素限定为Render
似乎有点可疑。将它用作缓存(例如,通过调用mutable
而不是调用Render
)并且您已经欺骗了编译器和类的用户。
修改强>
根据OP的评论,Render
方法确实是Render
的图形等价物。可能不会通过渲染来修改对象的“真实”状态(可能是为了构造最小工作示例而未示出)。将print_self()
指定为Render
方法是正确的做法。如果const
数据成员的原因是作为速度缓冲,以避免每次调用Cache
时构建和破坏它的成本,那么将Render
成员限定为Cache
(需要mutable
才能保留Render
)。
答案 2 :(得分:3)
我什么时候可以安全地说“此操作不会改变实例的内部状态”?
这个问题是合乎逻辑的。通常,可变成员不被视为内部状态,而是被视为实现工件。 所以,你班级的文档通常应该描述被认为是内部状态的内容,它可以单独留下可变成员。
const
仅涉及对象的内部状态。 const
- 方法可以合法地改变外部状态。在这里我想到了指针类比:char * const p
是一个常量指针,但它可以改变指向的值。所以你的资源管理器示例似乎也是正确的。
答案 3 :(得分:2)
正如@ildjarn所观察到的,const-correctness指的是可观察的,而不是对象的内部状态;这就是mutable
有用的原因。
然后再次,如果你实际渲染的东西,那么表示屏幕的对象的可观察状态不能合理地const
,恕我直言,因为如果你以后添加它会破坏一种检查方法,用于找出屏幕上/帧缓冲区中的内容。
如果SomeClass
不代表屏幕,那么我希望Render
可以引用一个Screen
对象的可变引用作为参数。从逻辑上讲,某些内容必须更改,即使它不是SomeClass
实例。
答案 4 :(得分:2)
正确性是关于从外部看到的对象的状态。
如果对成员函数的所有调用都继续返回相同的结果,则对象的状态在逻辑上是相同的。
答案 5 :(得分:2)
要问自己的问题是,“就用户而言,调用Render
函数是否会改变对象的已定义状态或未来行为?”
假设您的缓存实际上只是一个资源缓存,那么可能修改缓存并不会改变功能行为,只是让它更快。由于您的课程不能保证它的速度有多慢,因此就调用者而言,这不会改变已定义的状态或行为。因此,它是mutable
成员的有效候选人,可由const
成员函数修改。