C++ 为什么允许在初始值设定项列表中从常量指针到常量转换为常量指针到非常量
我看了贴在网上的问题 我仍然不明白为什么那个程序可以编译。我试图就这个问题发表我的意见,我不知道为什么它被删除了。所以我不得不再次问这个问题 这是节目单C++ 为什么允许在初始值设定项列表中从常量指针到常量转换为常量指针到非常量,c++,constructor,constants,implicit-conversion,C++,Constructor,Constants,Implicit Conversion,我看了贴在网上的问题 我仍然不明白为什么那个程序可以编译。我试图就这个问题发表我的意见,我不知道为什么它被删除了。所以我不得不再次问这个问题 这是节目单 class Cheater { public: Cheater(int avalue) : value(avalue), cheaterPtr(this) //conceptually odd legality in const Cheater ctor {} Cheater& getChea
class Cheater
{
public:
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) //conceptually odd legality in const Cheater ctor
{}
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr;
};
int main()
{
const Cheater cheater(7); //Initialize the value to 7
// cheater.value = 4; //good, illegal
cheater.getCheaterPtr().value = 4; //oops, legal
return 0;
}
我的困惑是:
const骗子骗子(7)
在构造函数中创建常量对象作弊器
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) //conceptually odd legality in const Cheater ctor
{}
“this”指针用于初始化cheaterPtr
我认为这是不对的checker
是一个const对象,其指针应该类似于:constchecker*constthis
这意味着它自身的指针和指针指向的对象都应该是常量,我们既不能更改指针的值,也不能修改指针指向的对象
但是对象cheater
的cheaterPtr
成员类似于cheater*const cheaterPtr
。这意味着指针是常量,但它指向的对象可以是非常量
正如我们所知,不允许将指针指向常量转换为指针指向非常量:
int i = 0;
const int* ptrToConst = &i;
int * const constPtr = ptrToConst; // illegal. invalid conversion from 'const int*' to 'int*'
如何在初始值设定项列表中允许从指向常量的指针转换为指向非常量的指针?到底发生了什么事
以下是我试图在原稿中对构造器中的“constness”的描述:
与其他成员函数不同,构造函数不能声明为const。当我们创建一个类类型的const对象时,该对象在构造函数完成对象初始化之前不会假定其“constness”。因此,构造函数可以在其构造过程中写入const对象
--C++Primer(第5版)P262 7.1.4构造函数如果构造函数是
常量
,它们就无法构造对象-它们无法写入其数据
您引用为“合法”的代码:
实际上是不合法的。在编译时,它的行为是未定义的,因为它通过非常量左值修改const
对象。与此完全相同:
const int value = 0;
const int * p = &value;
*const_cast<int*>(p) = 4;
const int value=0;
常量int*p=&value;
*const_cast(p)=4;
这也会编译,但它仍然是非法的(有UB)。如果构造函数是
const
,他们就不能构造他们的对象-他们不能写入它的数据
您引用为“合法”的代码:
实际上是不合法的。在编译时,它的行为是未定义的,因为它通过非常量左值修改const
对象。与此完全相同:
const int value = 0;
const int * p = &value;
*const_cast<int*>(p) = 4;
const int value=0;
常量int*p=&value;
*const_cast(p)=4;
这也会编译,但仍然是非法的(有UB)。您的假设是错误的。一次一个,第一个代码注释
class Cheater
{
public:
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) // NOTE: perfectly legal, as *this is non-const
// in the construction context.
{}
// NOTE: method is viable as const. it makes no modifications
// to any members, invokes no non-const member functions, and
// makes no attempt to pass *this as a non-const parameter. the
// code neither knows, nor cares whether `cheaterPtr`points to
// *this or not.
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr; // NOTE: member pointer is non-const.
};
int main()
{
// NOTE: perfectly ok. we're creating a const Cheater object
// which means we cannot fire non-const members or pass it
// by reference or address as a non-const parameter to anything.
const Cheater cheater(7);
// NOTE: completely lega. Invoking a const-method on a const
// object. That it returns a non-const reference is irrelevant
// to the const-ness of the object and member function.
cheater.getCheaterPtr().value = 4;
return 0;
}
你说:
我认为这是不对的。骗子是一个常量对象,其指针应该类似于:const-cheater*const-this
cheater
在构建之后是const
。在施工期间,它必须是非常量的。此外,构造函数不(也不能)知道调用方已指示对象将是const
。它所知道的只是构造一个对象的时间,所以它就是这么做的。此外,在构造之后,&作弊者
是常量作弊者*
。使实际指针var本身也const
在这种情况下是不适用的
然后
…object cheater的cheaterPtr成员类似于cheater*const cheaterPtr代码>
这实际上是一个非常准确的描述方式。因为cheater
是const
它的成员也是,这意味着cheaterPtr
成员是const
不它指向什么。您不能更改指针值,但因为它不是指向const对象的指针,所以您可以自由使用该指针修改它指向的对象,在本例中,它恰好是this
如果您希望指针及其指向的对象都是常量,您可以将其声明为constchecker*checkertr代码>在成员列表中。(顺便说一句,这样做只会使通过getCheaterPointer()
执行的可变操作无效。它还必须返回一个const-Cheater*
,这当然意味着赋值将失败
简而言之,这段代码是完全有效的。你想要看到的(调用方常量的构造感知)不是语言的一部分,如果你想让你的构造函数有自由…那么,构造就不可能了。你的假设是错误的。一次一个,首先是代码注释
class Cheater
{
public:
Cheater(int avalue) :
value(avalue),
cheaterPtr(this) // NOTE: perfectly legal, as *this is non-const
// in the construction context.
{}
// NOTE: method is viable as const. it makes no modifications
// to any members, invokes no non-const member functions, and
// makes no attempt to pass *this as a non-const parameter. the
// code neither knows, nor cares whether `cheaterPtr`points to
// *this or not.
Cheater& getCheaterPtr() const {return *cheaterPtr;}
int value;
private:
Cheater * cheaterPtr; // NOTE: member pointer is non-const.
};
int main()
{
// NOTE: perfectly ok. we're creating a const Cheater object
// which means we cannot fire non-const members or pass it
// by reference or address as a non-const parameter to anything.
const Cheater cheater(7);
// NOTE: completely lega. Invoking a const-method on a const
// object. That it returns a non-const reference is irrelevant
// to the const-ness of the object and member function.
cheater.getCheaterPtr().value = 4;
return 0;
}
你说:
我认为它不应该是对的。cheater是一个const对象,它的指针应该是这样的:const-cheater*const-this
checker
在构造之后是const
。在构造期间它必须是非const。此外,构造函数没有(也不能)知道调用者已经指出对象将是常量
。它所知道的只是它构造对象的时间,所以它就是这么做的。此外,构造后骗子
是常量骗子*
。使实际指针变量本身也常量
在这种上下文中根本不适用
然后
…对象骗子的骗子程序成员类似于骗子*const骗子程序;
这实际上是一种非常准确的描述方式。因为cheater
是const
它的成员也是,这意味着cheaterPtr
成员是const
;不是它指向的对象。你不能更改指针值,但因为它不是指向const对象的指针,你可以释放它y使用该指针修改它指向的内容,在本例中为h