Const методы, которые возвращают ссылки - PullRequest
15 голосов
/ 10 февраля 2011
class Foo
{
    int Bar;

    public:

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

Это нормально, что GetBar - это метод const? На самом деле это ничего не меняет, но предоставляет «внешнему миру» средства для его изменения.

Ответы [ 6 ]

19 голосов
/ 10 февраля 2011

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

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 голосов
/ 10 февраля 2011

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

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

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

3 голосов
/ 10 февраля 2011

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

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 голос
/ 10 февраля 2011

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

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

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

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

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

class A
{
  Foo * foo;

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

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

1 голос
/ 10 февраля 2011

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

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

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

g ++ фактически говорит:

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 голосов
/ 10 февраля 2011
Модификатор

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.

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

...