2012-03-21 26 views
2

想象一下,我有一个带有“show”成员函数的“Window”类,它使得底层窗口在屏幕上可见。当操作有明显的副作用时,Const成员函数

因为我打电话给一个基础的Windows API来实现这一点,我不以任何方式改变我的“窗口”对象的状态,但很明显,由于调用导致窗口状态发生很大的明显变化这(出现在屏幕上,并能窗口与用户进行交互)

所以,我要声明我的功能 -

void Window::show() const; 

因为据Window对象而言此功能没有按”不改变任何状态,因此可以在“const Window”对象上调用。但不知何故,在某种意义上,明确地调用该函数并不会改变对象的状态。

+1

同意。即使技术上可以做到这一点,也很难说它并没有违背“不变性”的概念。 – 2012-03-21 15:43:21

+0

考虑到这一点,能够让函数使用“const Window&”参数知道这些函数只能看到窗口,而不是完全改变它是很有价值的。 – jcoder 2012-03-21 15:46:53

回答

6

你可能正在处理的是C++没有纯度的概念,也就是说,函数是否有副作用。 const成员函数只承诺对象的状态不会被修改。

但是,有些对象在逻辑上由比实例包含的状态更多的状态组成。当一个对象的作用是与另一个库管理的状态进行交互时(特别是GUI库),这经常会出现。

因此,尽管show()可以顺便说一句标记const,它在逻辑上应该是。如果它确实是const,那么您会希望诸如is_visible()之类的函数在调用show()之前和之后返回相同的值,并且显然情况并非如此。

换句话说,const函数是那些没有改变对象,你可以通过其公共接口观察。这就是背后的推理,例如,标记一些成员函数const,但使用mutable成员来做内部簿记。

+0

嗯,好点。 – jcoder 2012-03-21 15:49:39

+1

很大程度上取决于你理解'Window'的抽象。我认为你可以用这两种方式来讨论这个问题。同样,你可以在任何函数上反对任何'const';像is_visible()这样的函数,如果它解析为窗口管理器的请求,可能会改变状态而不调用任何成员函数。 – 2012-03-21 16:13:38

+1

@JamesKanze:检索值可能会发生变化的函数('get_x()')与实际改变值('show()')的函数之间仍然存在差异。例如,在一个游戏中,您希望'get_x()'在当前时刻*返回一个对象*的'x'组件。随着时间的推移x'的变化来自别处,你只是在观察它们。 – 2012-03-21 16:23:20

2

如果您希望使用常量指针或引用来调用该函数,则必须将函数const标记为能够这样做。否则,这完全取决于你。

编辑:给这更多的想法。你的对象可能包含一个OS窗口的句柄,这个句柄可以传递给OS函数。这个句柄并没有真正的常量概念,所以它与C++的阻抗不匹配,但是你传递给它的函数要么是查询窗口属性(const),要么是以某种方式修改窗口(非const)。即使操作系统没有,你的对象也会强制执行常量概念。

+0

我了解C++语言的问题,这更多的是关于什么是好设计的问题。也许唯一的答案是“这要看...” – jcoder 2012-03-21 15:42:19

4

它可能不会改变Window对象内任何物理变量的任何状态,但它确实改变了Window所代表的事物的状态,所以我肯定会认为非const

4

这是古典逻辑常数与按位常量常量问题。当我学习C++(1990年代早期)时,曾经热烈地辩论过 ,但自从 那么,我认为有一个赞成逻辑const的共识:如果一个对象的逻辑状态发生变化,那么该函数不应该是 const(即使编译器将允许const),而如果逻辑 状态不改变,则函数应该是const(即使你 需要mutable或抛弃常量做;一个 的如缓存的结果计算)。

Window::show的具体情况下,很难说。是事实 该窗口正在显示其“逻辑状态”的一部分或没有。

0

通常你有这种情况:

  • 对于每个API窗口,最多有一个C++窗口对象。

  • C++窗口对象不可复制(包括它不可复制)。

对于这种情况下,可以在C++对象接口来使用const,以便让客户机代码由例如提供无状态变化的保证声明一些参数为const

但是,一旦一个或两个约束被删除,它就变成徒劳且无意义的练习。例如,考虑删除第二个约束,使C++对象可复制。这看起来似乎有道理,对待C++对象几乎就像shared_ptr实例(销毁除外)。

但是任何const shared_ptr都可以复制到非const之一,因此任何非const方法都可以很容易地调用。例如,shared_ptr::getconst方法,因此可以在const shared_ptr对象上调用它。但其结果是T*,即没有const传播到结果,因为即使它是T const*它不会真正限制客户端代码:客户端代码可能会将该const shared_ptr复制到非const之一,然后调用getconst实例。

尽管如此,与上述地方const(或在您的情况下不存在的const可以被在限制称为API窗口上的操作的可能有用的方式使用的事实都注册就,并不意味着它这样做一定是个好主意。

特别是,表示窗口的对象通常是事件接收器,根据我的经验,事件不会与const很好地混合。

但是,大多数程序员习惯于纯粹的检查员const。对于这种用法,只是提高代码的可读性,我会推荐const方法。例如,返回窗口大小的检查员在我看来应该比const更好。

+0

我同意不要复制,但是你可以传递一个const引用给需要的函数例如获取窗口的宽度和高度也许? – jcoder 2012-03-21 16:28:34