2013-09-10 4 views
2

я прочитал вопрос, размещенном на Why does C++ not have a const constructor?Почему преобразование из сопзЬ сопзЬ указатель на константный указатель на-на-nonconst в списке инициализатора позволило

Я до сих пор путают, почему эта программа может скомпилировать. И я попытался предложить свое мнение по этому вопросу, я не знаю, почему он был удален. Поэтому я должен снова задать вопрос.

Вот программа

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) создает константный объект мошенника, в его конструктор

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

'это' указатель был использован для инициализации cheaterPtr.

Я думаю, что это не должно быть правильно. cheater - объект const, который должен выглядеть примерно так: const Cheater* const this;, что означает, что указатель он сам и объект, на который указывает указатель, должны оба const, мы не можем ни изменить значение указателя, ни изменить объект, на который указывает указатель.

но объект cheatercheaterPtr участник что-то вроде Cheater* const cheaterPtr. Это означает, что указатель const, но объект, на который он указывает, может быть неконстом.

Как мы знаем, указатель на сопзЬ указатель к nonconst преобразования не допускается:

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

Как преобразование указателя к сопзЬ указателя к nonconst допускается в список инициализаторов? Что на самом деле произошло?

А вот Описана о «константности» в конструкторах я пытался предложить оригинальный пост:.

«В отличии от других функций-членов, конструкторы не могут быть объявлены как константы Когда мы создаем константный объект class object, объект не принимает свою «константу» до тех пор, пока конструктор не завершит инициализацию объекта. Таким образом, конструкторы могут писать объекты const во время их построения ».

++ Primer-C (5-е издание) P262 7.1.4 Конструкторы

ответ

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; 
} 

Вы сказали:

Я думаю, что это не должно быть правильным. Жулик является константным объектом, этот указатель должен быть что-то вроде: const Cheater* const this

cheaterявляетсяconstпосле строительства. Он должен быть неконстантным во время строительства. Кроме того, конструктор не знает (и не может) знать, что вызывающий абонент указал, что объект будет const. Все, что он знает, это время, чтобы построить объект, так что он делает. Кроме того, после строительство &cheater is const Cheater *. При этом фактический указатель var сам также const просто неприменим в этом контексте.

А потом ...

... член cheaterPtr объектного праведника что-то вроде Cheater* const cheaterPtr;

Это на самом деле невероятно точный способ описать это. Потому что cheater является const его членами также, что означает, что cheaterPtr член const; не То, что он указывает ,. Вы не можете изменить значение указателя, но поскольку он не является объектом-указателем-константе, вы можете свободно использовать этот указатель для изменения того, на что он указывает, что в данном случае является this.

Если вы хотите как указателя и его заостренный к объекту быть константными вы whould объявили как const Cheater *cheaterPtr; в списке участников. (И делает это, кстати, делает только то, что изменяемое действие через getCheaterPointer() недействительным. Он должен вернуть const Cheater*, а также, что означает, конечно, присвоение потерпит неудачу.

Короче говоря, этот код полностью действительным. Что вы хотите видеть (осведомленность о строительстве звонящих const-ness) не является частью языка, и действительно, это не может быть, если вы хотите, чтобы ваши конструкторы имели широту ... ну, конструкция.

+0

О, я понял, этот указатель не const, пока строительство не завершится. Но это кажется логически неправильным: вы говорите, что объект const, вы обещаете не изменять его, но позже вы можете использовать этот трюк, чтобы его изменить. Это недостаток C++? – Linlix

3

Если конструкторы были const, они не могли бы построить свой объект - они не могли писать в своих данных!

код вы цитируете, как "юридический:"

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

это на самом деле не законно. Пока он компилируется, его поведение не определено, поскольку оно изменяет объект const через неконсольное lvalue. Это точно так же, как это:

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

Это будет также обобщать, но это по-прежнему незаконно (есть UB).

+0

Вы имеете в виду, что существует неявный const_cast? – Linlix

+0

@Linlix No. В ctor у вас есть указатель non-const для объекта, который называется 'cheater' в' main() '. Вы храните это po среди. Когда ctor выйдет, 'cheater' станет' const'. У вас все еще есть указатель неконстантный для него. Если вы разыскиваете этот сохраненный указатель и используете его для модификации 'cheater', вы изменяете объект' const' через не const const lvalue, поэтому вы получаете UB. – Angew

Смежные вопросы