2

我阅读了 为什么 C++ 没有 const 构造函数?

我仍然很困惑为什么该程序可以编译。我试图就这个问题发表我的看法,我不知道为什么它被删除了。所以我不得不再次问这个问题。

这是程序

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 Cheater cheater(7) 在其构造函数中创建一个 const 对象作弊器

  Cheater(int avalue) :
    value(avalue),
    cheaterPtr(this) //conceptually odd legality in const Cheater ctor
{}

'this' 指针用于初始化cheaterPtr.

我觉得应该不对。cheater是一个const对象,它的this指针应该是这样的:const Cheater* const this;这意味着它自己的指针和指针指向的对象都应该是const,我们既不能改变指针的值,也不能修改指针指向的对象。

但 objectcheatercheaterPtr成员类似于Cheater* const cheaterPtr. 这意味着指针是 const 但它指向的对象可以是非常量。

我们知道,指针到常量到指针到非常量的转换是不允许的:

int i = 0;
const int* ptrToConst = &i;
int * const constPtr = ptrToConst;  //  illegal. invalid conversion from 'const int*' to 'int*'

如何在初始化列表中允许从指针到常量到指针到非常量的转换?到底发生了什么?

这是我试图提供给原始帖子的构造函数中关于“常量”的描述:

“与其他成员函数不同,构造函数可能不会被声明为 const。当我们创建一个类类型的 const 对象时,该对象在构造函数完成对象的初始化之前不会假定它的‘常量’。因此,构造函数可以写入 const建造过程中的物体。”

--C++ Primer (5th Edition) P262 7.1.4 构造函数

4

2 回答 2

3

如果构造函数是const,他们就不能构造他们的对象——他们不能写入它的数据!

您引用为“合法”的代码:

cheater.getCheaterPtr().value = 4;    //oops, legal

实际上是不合法的。当它编译时,它的行为是未定义的,因为它const通过一个非常量左值修改一个对象。它与此完全相同:

const int value = 0;
const int * p = &value;
*const_cast<int*>(p) = 4;

这也将编译,但它仍然是非法的(有 UB)。

于 2013-09-10T07:53:18.373 回答
1

你的假设是不正确的。一次拿一个,第一个代码注释。

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 对象,它的 this 指针应该是这样的:const Cheater* const this

cheater const 施工后在构造过程中它必须是非常量的。此外,构造函数不(也不可能)知道调用者已指示对象将是const. 它所知道的只是构建对象的时间,所以它就是这样做的。此外,施工&cheaterconst Cheater *. 使实际的指针 var 本身const在这种情况下也根本不适用。

接着...

...对象作弊者的 cheaterPtr 成员类似于Cheater* const cheaterPtr;

这实际上是一种非常准确的描述方式。因为cheaterisconst它的成员也是,这意味着cheaterPtr成员是const; 不是它所指向。您不能更改指针值,但由于它不是指向 const 对象的指针,您可以自由地使用该指针来修改它所指向的内容,在这种情况下恰好是this.

如果您希望指针及其指向的对象都为 const,您应该将其声明为const Cheater *cheaterPtr;成员列表中。(顺便说一句,这样做只会使getCheaterPointer()无效的动作发生变化。它也必须返回 a const Cheater*,这当然意味着分配会失败。

总之,这段代码是完全有效的。您想看到的(调用者const-ness 的构造意识)不是语言的一部分,如果您希望构造函数具有...的自由度,那么它确实不可能......好吧,construct

于 2013-09-10T08:29:40.370 回答