const成员函数保证成员函数不能更改任何成员变量,除非它们被标记为可变。
那是说它什么都不保证?
这是一个真实的例子。我有一个课程EventHandler
和EventDispatcher
。
class EventHandler
{
public:
void registerHandler(EventHandler* handler) const // Should this be a const?
{
EventDispatcher::registerHandler(handler);
}
};
EventDispatcher // Singleton Class
{
public:
void registerHandler(EventHandler* handler)
{
mListeners.push_back(handler);
}
private:
std::vector<EventHandler*> mListeners;
};
EventDispatcher
的{{1}}应该是const吗?它不会更改其成员变量,但会改变全局状态。
答案 0 :(得分:3)
正确,它不保证除了对象本身之外的任何其他状态。我会说没有特别要求它不会修改全局状态。 [如果你把它带到极端,任何函数调用都会修改处理器的当前状态 - 即使它只是将返回地址存储在堆栈[1]]。
但更合理的是const
成员函数如下:
class myclass
{
private:
std::vector<int> v;
public:
std::vector<int> getV() const { return v; }
};
这将创建向量v
的副本 - 它又分配内存(从而改变全局状态)。将对象提供给输出流的输出函数也是类似的。
如果一个成员函数修改某个全局状态(以一种不明显的方式),那么它可能应该在函数的描述中明确(文档有时是有用的)。
[1]当然,C ++和C标准没有声明处理器必须有堆栈,返回地址等 - 编译器可以内联所有代码,而不是进行任何“调用”,或者用魔法来“记住”回到哪里 - 只要魔法真的有效,依靠它就可以了。
根据您编辑过的问题进行修改:
这是在任何一个方向上并不完全明显的那些之一,你会期望registerHanlder
做一些像“将处理程序对象存储在某个地方”的东西。但由于它不会修改对象本身,因此可能有助于解释它正在更新调度程序类。当然,如果它实际上没有更新类本身,或者使用类中的任何东西,你可能应该使它static
而不是const
- 这样很明显它实际上并没有修改对象本身。
除此之外:在编写时,您的代码将无效,因为EventDispatcher::registerHandler
不是静态成员,而您的EventHandler::registerHandler
并未引用EventDispatcher
的实例。您可能必须将EventDispatcher
的实例作为全局变量,或使EventDispatcher::registerHandler
成为静态函数,并使mListeners
成为静态成员。或者其他类似的东西。
答案 1 :(得分:2)
保证是合同提醒,而不是“物理”记忆障碍。
因此,如果正确实现const
关键字,编译器将能够帮助检测可能的错误。
但是,没有C / C ++编译器会停止您直接修改成员状态;既不是通过字段也不是通过将对象引用转换为指针并修改底层内存。
不允许const
方法更改系统的外部行为,但const
方法更改内部状态完全可以接受即可。
换句话说,在随机调用所有const
方法几次后,系统仍应提供与最初相同的行为。
另一方面,如果const
方法感觉缓存耗时的计算并将其重新用于下一次调用,则应该允许它。记录统计信息的记录器类也是如此,但不会改变系统的行为。