2011-02-10 4 views
15
class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return Bar; 
    } 
} 

Вполне ли это, что GetBar - это метод const? На самом деле это ничего не меняет, но оно обеспечивает «внешний мир» средством его изменения.Const Методы, которые возвращают ссылки

+0

Думаю, вы уже ответили на свой вопрос. Кроме того, в примере Bar уже открыт. – XAder

+0

'& Bar' имеет тип' const int * ', а не' int & '. Вы, компилятор, должны сказать вам, что это не нормально. –

+0

Вы пытались скомпилировать? Что рассказал вам компилятор? –

ответ

18

У вас есть опечатка в коде, это то, что вы, вероятно, имели в виде:

class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return Bar; // Removed the ampersand, because a reference is returned, not an address 
    } 
} 

И нет, это не законно ,При пометке метода с помощью const вы не только обещаете, что не будете касаться какого-либо внутреннего состояния объекта, вы также обещаете, что не вернете ничего, что может быть использовано для изменения состояния объекта. Неконстантная ссылка может использоваться для изменения значения Bar вне диапазона GetBar(), поэтому вы подразумеваете, что вы не можете выполнить обещание.

Вы должны либо изменить метод, чтобы быть неконстантным, либо возвратить ссылку на константу, либо сделать Bar освобожденным от обещания, обозначив его как mutable. Например: mutable int Bar; Ключевое слово mutable сообщает компилятору, что логическая константа объекта не зависит от состояния Bar. Тогда вам разрешено делать все, что вам угодно.

4

Неа, так как вы не можете сделать следующее назначение: const int x; int &y = x;

Что вы можете сделать, хотя это const int x; const int &y = x;

И, конечно, нет никаких проблем в перегрузке методы и создании как сопзЬ и неконстантного варианты.

3

Возможно, вы захотите вернуть Bar, а не &Bar. Во всяком случае, я уронил этот код в Комео:

class Foo 
{ 
    int Bar; 

    public: 

    int& GetBar() const 
    { 
     return &Bar; 
    } 
}; 

int main(int argc, char** argv) 
{ 
    Foo x; 
    int y = x.GetBar(); 
    y = 5; 
    return 0; 
} 

И получил ошибку:

line 9: error: qualifiers dropped in binding reference of type 
      "int &" to initializer of type "const int" 
      return Bar; 
       ^
1

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

Тогда нет, вы не можете этого сделать; в методе const у вас есть constthis указателя (в вашем случае это будет const Foo *), что означает, что любые ссылки вы можете получить его полей будет const ссылка, так как вы к ним доступ через " const путь ".

Таким образом, если вы пытаетесь сделать то, что вы сделали в этом коде, вы получите ошибку компиляции, так как вы пытаетесь инициализировать int & (возвращаемое значение вашего метода) с const int & (ссылками вы получить от Bar), что, очевидно, запрещено.

г ++ на самом деле говорит:

testconstref.cpp: In member function ‘int& Foo::GetBar() const’: 
testconstref.cpp:9: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘const int*’ 

, который я только что сказал. :)

Если вы вернете ссылку const на поле класса из метода const, у вас не будет проблем.


  1. исключающих поля помечены как mutable, который сообщает компилятор, что такие поля являются модифицируемыми даже const методов; это исключение было введено, чтобы позволить const методам изменять «реальное» состояние объекта в случаях, когда это не изменяет его «логическое» состояние; это может быть полезно для реализации ленивых вычислений, подсчета ссылок, ...
0

const модификатор функции-члена не позволяет изменять состояние объекта в его области. Компилятор просто проверяет, изменяет ли эта функция состояние объекта или нет в его области. Сделав еще один пример -

class foo 
{ 
    int num ; 
    public : 
     foo(int anum) 
     { 
      anum = 10; 
     } 
     int getNum() 
     { 
      return num; 
     } 
}; 

foo obj; 
int& myNum = obj.getNum() ; // myNum is just an alias to the private class variable num 
myNum = 40; // Actually changes the content of the private variable. 

Таким образом, компилятор проверяет только спецификаторы доступа (то есть, является ли эта переменная доступна или нет в этой области), но не о месте памяти открытого/закрытого/Защищенные переменной в случае возвращения в какой-либо другой переменной ,

1

Члены вашего класса считаются const, когда вы находитесь в методе const. Итак, хотя Bar - int в вашем классе, а не const int, в контексте GetBar() const это «const int». Поэтому возвращение его в качестве неконстантного ссылки или указателя, так же незаконно, как делают:

const int y = 57; int& z = y;

Это нарушает константный-корректность, даже если вторая линия на самом деле не изменилось ничего (пока) в у.

Обратите внимание, что если у вашего класса есть указатели, единственное, что является const, это сами указатели, а не то, на что они указывают. (Часто упоминаются как «мелкая» константность)

Таким образом, это будет законным:

class A 
{ 
    Foo * foo; 

    public: 
    Foo * getFoo() const // legal. does not have to return const Foo * 
    { 
     return foo; 
    } 
}; 

Обратите внимание, что в исходном коде вам будет позволено вернуться Bar по неконстантной ссылке, если бы это было mutable, потому что эти члены не связаны константой функций-членов.

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