C++ 类内与类外强制转换int的常量
我在维基百科的页面上读到比亚恩·斯特劳斯特鲁普建议将NULL定义为 常数int NULL=0 如果“你觉得你必须定义空值”,我立刻想,嘿。。等等,康斯特演员怎么样 经过一些实验,我发现C++ 类内与类外强制转换int的常量,c++,C++,我在维基百科的页面上读到比亚恩·斯特劳斯特鲁普建议将NULL定义为 常数int NULL=0 如果“你觉得你必须定义空值”,我立刻想,嘿。。等等,康斯特演员怎么样 经过一些实验,我发现 int main() { const int MyNull = 0; const int* ToNull = &MyNull; int* myptr = const_cast<int*>(ToNull); *myptr = 5; printf("MyN
int main() {
const int MyNull = 0;
const int* ToNull = &MyNull;
int* myptr = const_cast<int*>(ToNull);
*myptr = 5;
printf("MyNull is %d\n", MyNull);
return 0;
}
intmain(){
常量int MyNull=0;
常量int*ToNull=&MyNull;
int*myptr=const_cast(托努尔);
*myptr=5;
printf(“MyNull是%d\n”,MyNull);
返回0;
}
将打印“MyNull为0”,但如果我使常量int属于一个类:
class test {
public:
test() : p(0) { }
const int p;
};
int main() {
test t;
const int* pptr = &(t.p);
int* myptr = const_cast<int*>(pptr);
*myptr = 5;
printf("t.p is %d\n", t.p);
return 0;
}
类测试{
公众:
test():p(0){}
常数INTP;
};
int main(){
试验t;
常数int*pptr=&(t.p);
int*myptr=const_cast(pptr);
*myptr=5;
printf(“t.p是%d\n”,t.p);
返回0;
}
然后打印“t.p是5”
为什么两者之间有区别?为什么在我的第一个示例中,“*myptr=5;”会自动失败,如果有,它会执行什么操作?首先,在这两种情况下,您都是通过修改常量变量来调用未定义的行为 在第一种情况下,编译器将
MyNull
声明为常量,并将main()中对它的所有引用替换为0
在第二种情况下,由于
p
在一个类中,编译器无法确定它是否可以将所有classInstance.p
替换为0
,因此您可以看到修改的结果。首先,在这两种情况下,您都通过尝试修改常量变量来调用未定义的行为
在第一种情况下,编译器将MyNull
声明为常量,并将main()中对它的所有引用替换为0
在第二种情况下,由于
p
在一个类中,编译器无法确定它是否可以将所有classInstance.p
替换为0
,因此您可以看到修改的结果。首先,在第一种情况下,编译器很可能会翻译您的
printf("MyNull is %d\n", MyNull);
直接进入
printf("MyNull is %d\n", 0);
因为它知道const
对象在有效程序中永远不会改变。您试图更改常量
对象会导致未定义的行为,这正是您观察到的。因此,暂时忽略未定义的行为,从实际的角度来看,很可能您的*myptr=5
成功地修改了Null
。只是您的程序并不真正关心您现在的Null
中有什么内容。它知道Null
为零,并且将始终为零,并相应地执行操作
其次,为了根据您所引用的建议定义NULL
,您必须将其具体定义为积分常量表达式(ICE)。你的第一个变种确实是冰。您的第二个变体不是。ICE中不允许类成员访问,这意味着您的第二个变体与第一个变体明显不同。第二个变量没有为NULL
生成可行的定义,并且您将无法使用test::p
初始化指针,即使它被声明为const int
并设置为零
SomeType *ptr1 = Null; // OK
test t;
SomeType *ptr2 = t.p; // ERROR: cannot use an `int` value to initialize a pointer
至于第二种情况下的不同输出。。。未定义的行为就是未定义的行为。这是不可预测的。从实际的角度来看,您的第二个上下文更复杂,因此编译器无法预先进行上述优化。i、 您确实成功地突破了语言级别的限制并修改了const限定变量。语言规范并不能使编译器轻松(或可能)优化出类的const
成员,因此在物理级别上,p
只是驻留在该类的每个对象内存中的类的另一个成员。你的黑客只是修改了记忆。但这并不意味着它是合法的。这种行为还没有定义
当然,这一切都是毫无意义的。看起来这一切都是从“const_cast怎么样”的问题开始的。那怎么办<代码>const_cast从未打算用于此目的。不允许修改
const
对象。使用const_cast
,或不使用const_cast
——都无所谓 首先,在第一种情况下,编译器最有可能翻译您的
printf("MyNull is %d\n", MyNull);
直接进入
printf("MyNull is %d\n", 0);
因为它知道const
对象在有效程序中永远不会改变。您试图更改常量
对象会导致未定义的行为,这正是您观察到的。因此,暂时忽略未定义的行为,从实际的角度来看,很可能您的*myptr=5
成功地修改了Null
。只是您的程序并不真正关心您现在的Null
中有什么内容。它知道Null
为零,并且将始终为零,并相应地执行操作
其次,为了根据您所引用的建议定义NULL
,您必须将其具体定义为积分常量表达式(ICE)。你的第一个变种确实是冰。您的第二个变体不是。ICE中不允许类成员访问,这意味着您的第二个变体与第一个变体明显不同。第二个变量没有为NULL
生成可行的定义,并且您将无法使用test::p
初始化指针,即使它被声明为const int
并设置为零
SomeType *ptr1 = Null; // OK
test t;
SomeType *ptr2 = t.p; // ERROR: cannot use an `int` value to initialize a pointer
至于第二种情况下的不同输出。。。未定义的行为就是未定义的行为。这是不可预测的。从实际的角度来看,您的第二个上下文更复杂,因此编译器无法预先进行上述优化。i、 你确实成功地突破了