如何解决C ++,类,常量和奇怪的语法
| 我今天正在重新阅读c ++入门(第四版)-有关成员函数和const引用等部分,然后我想到了这个奇怪的小程序:using std::cout;
using std::endl;
class ConstCheater
{
public:
ConstCheater(int avalue) : ccp(this),value(avalue) {}
ConstCheater& getccp() const {return *ccp;}
int value;
private:
ConstCheater* ccp;
};
int main()
{
const ConstCheater cc(7); //Initialize the value to 7
cout << cc.value << endl;
cc.getccp().value = 4; //Now setting it to 4,even though it\'s const!
cout << cc.value << endl;
cc.value = 4; //This is illegal
return 0;
}
我的问题是-为什么C ++允许这样的语法?为什么在声明为const的类中编辑普通数据成员? const的POINT不是为了使您无法修改值吗?
解决方法
我会说托尼(Tony)标记为正确的答案是错误的,而迈克尔·伯尔(Michael Burr)的答案是正确的。
更明确地说出他的话(至少对我来说):
有两个可能引起误解的地方:
隐式const的工作方式
在构造const对象期间解释
this
的方式
1.隐式常量
隐式const(当成为const
时在ConstCheater
内部的含义)不会将cc
变成pointer-to-const
而是变成const-pointer
,也就是说,当您执行此操作时:
const ConstCheater cc(7);
内部来自:
ConstCheater * ccp;
...至...
ConstCheater * const ccp;
而不是...
const ConstCheater * ccp;
这可能是预期的。
2.const
物体的构造
不过,更奇怪的是,允许将this
传递给构造函数中的cpp
\的初始值设定项,因为人们认为ѭ1should应被视为pointer-to-const
,因此不是传递给const-pointer
的有效值。
这就是说人们可能会期望:
...: ccp(this) ... // expected to fail but doesnt
之所以失败,是因为从概念上讲,您可能希望这等效于:
const ConstCheater cc(7);
const ConstCheater * const this = &cc; // const-pointer-to-const
因此,您会认为:
ConstCheater * const ccp = this; //expected error!
会失败!但这不是因为显然在构造过程中显然将this
当作是:
const ConstCheater * this = &cc;
因此该对象在构造过程中实际上不是常量。
我不确定我是否完全理解其原因,但迈克尔·伯尔(Michael Burr)指出,提供预期行为似乎存在逻辑和技术障碍,因此该标准似乎可以消除当前有些奇怪的行为。
我最近问了一个相关的问题:为什么C ++没有const构造函数?但是到目前为止,我还没有真正完全理解为什么它站不住脚的原因,尽管我认为这将给C ++开发人员带来负担,他们必须为他们想要创建const对象的任何类定义一个笨拙的const构造函数。 。
,即使getccp()
是const
方法,它也不保证您对返回的引用进行操作。该方法本身不会修改对象,因此不会违反规则。
如果返回a24ѭ,那就不一样了。
如您的示例所示,const
的复杂性远不只是将其应用于对象。 C ++常见问题解答中有一个有关const正确性的部分,尤其涉及您在此处强调的情况。
,允许构造函数修改“ 3”对象的值,是的。但是,如果不是,那该怎么办呢?
由于构造函数具有这种访问权限,因此可以将其“转发”给其他人或“保存”以供以后使用。当然,这样做可能不是一个好主意。
在这种情况下,C ++的安全机制不会阻止您构建格式错误的程序。 C ++并非万无一失。因此,请小心!
,在构造函数完成其操作之前,对象不会变为const。因此,“ 1”是存储非常量内存的指针,但此后不久便发生变化。这就是为什么它首先允许分配的原因,因为您没有做错任何事情。这意味着ѭ13是指向const的指针,但是编译器没有意识到这一点。它没有办法;毕竟,您将其声明为非常量。这仍然是未定义的行为,不是您的编译器真正希望能够帮助您捕获的类型。
,真正的问题不是ѭ29的行为-行上没有错误:
const ConstCheater cc(7);
它使用应为constwith1ѭ指针的指针初始化非const指针。但是,构造函数不能为const
(9.3.2 / 5,但是稍加思考,就应该清楚为什么)。因此,允许构造函数使用指向const对象(或即将成为const的对象)的指针来初始化非const指针。那就是你在开车的洞。
关于为什么允许它,我想标准很难尝试去封闭漏洞,因为它必须枚举构造函数的ѭ1all必须被视为const
的所有方式以及所有方式。构造const对象时,必须将其视为“ 35”。这似乎是一项艰巨的任务。
,您的对象不是完全不变的:它只是您创建的指向它的引用,它是恒定的。
,您正在制作const
是指ConstCheater
。 ConstCheater
中的任何内容都不会使value
成为const
。
,const
限定符限制在对象上调用非const方法,因此问题是您的设计允许您通过const方法为成员提供非const引用。
常见的方法是
Member& getccp() {return *member;}
const Member& getccp() const {return *member;}
在某些情况下,如果对象的逻辑一致性不受其成员的外部修改的影响,则可以允许
Member& getccp() const {return *member;}
逻辑和形式常数差异的另一个例子是mutable
成员。即mutable可以是在最后一个“ 3”方法调用时计算的术语,如果您在下一次调用时获得相同的输入,则可以轻松地返回存储的值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。