2009-07-31 3 views
2

У меня есть два члена геттер:Почему C++ не допускает const-const преобразование в copy ctor?

Node* prev() { return prev_; } 
int value() { return value_ } 

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

Node(Node const& other) : prev_(other.prev()), value_(other.value()) { } 

Компилятор отклоняет это. Я думал, что C++ позволяет неконстантный к сопзЬ преобразованию в параметрах функции, такие как:

{ 
    Foo(int bar); 
} 

Foo(const int bar) 
{ 
    //lala 
} 

Почему не он позволил мне сделать то же самое с конструктором копирования? Идентификатор const означает, что я обещаю ничего не менять, так почему это имеет значение, если я получу свое значение из источника const или non-const?

ответ

14

Вы не пытаетесь выполнить преобразование const без const. Вы пытаетесь вызвать два метода, которые не являются константной ссылкой (вызовы prev и value). Этот тип операции строго запрещен семантикой const.

Вместо этого вы можете использовать поля prev_ и value_ напрямую. Поскольку он является одним и тем же типом, вы можете получить доступ к частным лицам, которые будут доступны для объекта const.

2

Вы правы - const означает, что вы обещаете ничего не менять. Компилятор заставляет вас сдержать свое обещание, не позволяя вам вызывать методы на этом объекте, которые сами не обещают ничего не менять.

+0

Стоит ли столбце const после круглых скобок моей копии ctor, что они НЕ МОГУТ мутировать данные других? – jkeys

+0

Дело не в конструкторе, а в аксессорах, которые не являются константами, поэтому нельзя вызвать объект const. – Javier

+0

Итак, мой компилятор просто параноик. Даже если мои помощники не мутируют данные, конструктор копирования этого не знает? – jkeys

3

Я думал, что C++ позволяет неконстантный на константные преобразования в параметрах функции, такие как:

Вы пытаетесь сделать прямо противоположное: Const к неконстантному. Вызывая не-const-функцию-член, компилятор свяжет выражение (которое является Node constNode& для привязки указателя this). Таким образом, он отключит const - не разрешен, потому что он вызовет функцию non-const для объекта const.

/* class Foo */ { 
    Foo(int bar); 
} 

/* Foo:: */ Foo(const int bar) 
{ 
    //lala 
} 

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

Если вам интересно: Если вышеуказанные две версии идентичны - почему не ниже? Тогда это связано с тем, что ниже приведен еще один уровень косвенности: ниже, сама ссылка (верхнего уровня) не const (вы не можете напрямую поставить const на ссылку), но тип, на который ссылается, является const. В это время константа не игнорируется при определении типа функции.

/* class Foo */ { 
    Foo(int &bar); 
} 

// different thing, won't work! 
/* Foo:: */ Foo(const int &bar) 
{ 
    //lala 
} 
2

В объявлении конструктора Node(Node const& other) Аргумент other объявлен const. Это означает, что вы можете называть только const методов.

Вы вызываете other.prev() и other.value() от конструктора, оба из которых не являются const, поэтому компилятор жалуется.

2

Как уже упоминалось, вы вызываете методы non-const для объекта const, который компилятор не разрешит.

Простой исправить это просто пометить функции геттер как константы:

Node* prev() const { return prev_; } 
int value() const { return value_; } 

, так как они не изменяют объект; теперь их можно вызвать с помощью объекта const. На самом деле это, вероятно, должно быть сделано в любом случае, чтобы пользователи класса могли вызывать те геттеры с объектами const.

Тем не менее, есть еще одна потенциальная проблема в том, что если ваша копия т е р выглядит следующим образом:

Node(Node const& other) : prev_(other.prev()), value_(other.value()) { } 

копия и оригинал будет указывают на один и тот же объект Node в их prev_ член. В зависимости от семантики класса это может быть ОК, но это может быть проблема собственности или другая логическая несогласованность.

+1

Хорошая уловка по вопросу собственности. –