Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 类内与类外强制转换int的常量_C++ - Fatal编程技术网

C++ 类内与类外强制转换int的常量

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

我在维基百科的页面上读到比亚恩·斯特劳斯特鲁普建议将NULL定义为

常数int NULL=0

如果“你觉得你必须定义空值”,我立刻想,嘿。。等等,康斯特演员怎么样

经过一些实验,我发现

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、 你确实成功地突破了