2015-05-31 3 views
0
class A 
{ 
public: 
    A(int i = 25) {x = i;y=new int[i];for(int j=0;j<i;j++) y[j]=j;} 
    int& f() const {return x;} 
    int& operator[](int i) const {return y[i];} 

private: 
    int x,*y; 
}; 

int main() 
{ 
    A a(15); 
    cout << a[5]; 
    cout << a.f(); 

    return 0; 
} 

Когда я пытаюсь скомпилировать код он говоритInt & на константные INT -static против dynamic-

"Invalid initialization of reference of type int& from expression of type const int" 

относительно функции f().

Я понимаю это, поскольку он возвращает неконстантную ссылку на что-то, объявленное функцией const. Но не должно ли оно вести себя одинаково с перегрузкой []?

Он также возвращает неконстантную ссылку на то, что функция объявлена ​​как const, но там нет ошибки. В чем разница?

ответ

2

Сообщается, что вы не можете вернуть ссылку на константу без ссылки на элемент данных из функции-члена const.Вам нужно

const int& f() const {return x;} 

в случае необходимости Вы можете принять решение о предоставлении неконстантных перегрузок:

int& f() {return x;} 

Что касается operator[], он не возвращает ссылку на член данных. Вы не можете изменить x или y через operator[], так что это действительно функция члена const. Вы можете отказаться от модификации данных , указанных в, y, и это будет иметь смысл, если ваш класс моделирует массив. Но это не является строго необходимым, и у компилятора нет причин для его принудительного применения.

const int& operator[](int i) const {return y[i];} 
int& operator[](int i) {return y[i];} 
+0

Да, я это понял. Но разве он не должен говорить то же самое о функции перегрузки []? – flaviumanica

+0

@flaviumanica Это не возвращает ссылку на элемент данных. – juanchopanza

2

вопрос здесь:

int& f() const {return x;} 

Ваша функция отмечена const, поэтому она может быть вызвана только const экземплярами. Тем не менее, вы возвращаете ссылку не const, поэтому, если она действительна, вы можете использовать ее для модификации const экземпляров. Компилятор не доволен этим. Следовательно, f() должен возвращать const int&.

С другой стороны, int& operator[](int) const скомпилирует, так как вы возвращаете ссылку на данные, на которые указывает указатель y, но вы не можете изменить сам указатель. Другими словами, на примере const указатель y равен const, то есть int * const y, но не данные. Поэтому побитовое const -ness сохраняется, но, конечно, логическое const -ness нет, однако компилятор только заботится о поразрядном const -ness.

Чтобы применить логическую const правильность, один вариант состоит в написании 2 версии вашего operator[]:

const int& operator[](int i) const {return y[i];} 

и

int& operator[](int i) {return y[i];} 

Обратите внимание, что вторая версия должна быть отмечена не- const, иначе вы попытаетесь перегрузить две функции, которые отличаются только их возвращаемым типом. Если вы хотите, чтобы избежать дублирования кода в не- const версии, вы можете использовать версии const через const_cast, как

int& operator[](int i) 
{ 
    return const_cast<int&>(const_cast<const A&>(*this)[i]); // use the const version 
} 

EDIT

Существует предложение ввести const - распространяющихся обертку для указателей типа элементов данных, propagate_const, что в действительности будет также сделать данные указывают на const, см

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4057.pdf

0

В языке С ++ константность класса подразумевает немедленное константность всех его членов (за исключением тех, mutable). Однако константа класса не распространяется на данные , указанные указательными элементами или , на которые ссылаются ссылочные члены. Эти данные с указанием/ссылкой не являются частью класса, и на его константу не влияет стабильность этого класса.

В вашем примере, объявление функции члена, как const делает его лечить членов x и y в const. Однако данные, обозначенные y, не становятся const, например. ни *y, ни y[i]const.

Распространение константы от охватывающего класса до заостренных/ссылочных данных фактически является частью намерения пользователя. Это то, что вам нужно или не нужно в зависимости от того, что вы пытаетесь реализовать. Язык оставляет его полностью для вас (или для решения на уровне библиотеки).

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