Зачем нужна как константная ссылка, так и константная функция-член?

Я выполняю упражнения из «Принципов и практики программирования с использованием C++» и нашел класс с этой функцией-членом здесь:

const vector<string> &get_name() const { return name; }

где имя — вектор: vector< string> name;

В книге пока представлены 2 концепции (до страницы 235):

  1. вернуть константную ссылку, чтобы функция не изменила возвращаемое значение:

    const vector<string> &get_name() { return name; } 
    
  2. константная функция-член, которая не может изменять объект. в этом случае это будет так:

    vector<string> get_name() const { return name; } 
    

Может быть, я не совсем понимаю, но разве эти две концепции не совпадают? Не желая менять вектор "имя".

Зачем нужны оба "const"?

Спасибо всем, кто найдет время ответить!


person Theodore    schedule 17.06.2020    source источник
comment
Они не совпадают, потому что вторая версия должна сделать (потенциально затратную) копию name.   -  person François Andrieux    schedule 17.06.2020
comment
Сначала const применяется только к возвращаемому объекту, и метод не может быть вызван для константного экземпляра/объекта. второй применяется к экземпляру/объекту, поэтому оба константных/неконстантных экземпляра могут вызывать этот метод.   -  person Jarod42    schedule 17.06.2020
comment
В первом говорится, что вам не разрешено менять то, о чем вы просите, и я могу измениться, пока вы просите, во втором говорится, что я не собираюсь меняться, если вы попросите об этом, и вы можете делать все, что захотите. хочу с вещью, которую я даю вам. Это не одно и то же понятие.   -  person molbdnilo    schedule 17.06.2020


Ответы (3)


  1. вернуть константную ссылку, чтобы функция не изменила возвращаемое значение
  2. константная функция-член, которая не может изменять объект. в данном случае было бы так

Это могло бы быть немного яснее, я попытаюсь объяснить это лучше.

Возврат константной ссылки предотвращает изменение возвращаемого объекта вызывающими объектами.

Вот пример:

// let get_name be `const std::vector<std::string>& get_name()`

np1.get_name().size(); // ok, size is a const function of vector
np1.get_name().push_back("hello"); // ERROR! push_back is not a const function of vector

Так что действительно, вызывающая сторона не может изменить вектор name. Тип возвращаемого значения является const квалифицированным.

Однако, если сама функция get_name не является константной (не возвращаемый тип), то ей разрешено изменить имя из самого класса.

Видите ли, функции-члены получают скрытый параметр this, который является указателем на вызываемый объект. Указатель может указывать либо на константный объект, либо на изменяемый объект. Вот сравнение:

// returning const ref, callers cannot change the name vector
const std::vector<std::string>& get_name() {
    // The function receive a `this` that points to a mutable,
    // we can change the name from the inside
    this->name.push_back("another");
    return name;
}

// the `this` pointer points to const -----v---v
const std::vector<std::string>& get_name() const {
    this->name.push_back("another"); // ERROR! Cannot mutate member of const object
    return name;
}

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

Например, не только вы знаете, что функция vector::size() не изменит вектор, но и компилятор гарантирует это, поскольку это функция-член, квалифицированная как const.

И, наконец, код, который вы разместили здесь:

vector<string> get_name() const { return name; } 

Это не вернет ссылку, но сделает копию. Вызывающий может изменять копию по своему усмотрению, но не может изменять сам name.

Вот пример измененной копии:

auto name_copy = np1.get_name();

name_copy.push_back("another name"); // works, we mutated the copy by adding an element
person Guillaume Racicot    schedule 17.06.2020
comment
Большое спасибо, Гийом! это действительно помогает. Если я могу задать другой вопрос, как изменить копию последней строки: vector‹string› get_name() const { return name; } - person Theodore; 18.06.2020
comment
не могли бы вы взглянуть на мой код здесь? github.com/ltr01/PPPCpp-Tests/blob/master/9.3 _test2.cpp Я определил функции get_name1(), get_name2() и get_name3(), как в ваших примерах. И функции 1 и 2 ведут себя именно так, как вы сказали. Но после создания объекта np3 и добавления к нему другого элемента я все еще не вижу этот новый элемент. Я что-то делаю не так или до сих пор чего-то не понимаю? Большое спасибо, что нашли время для этого! Это действительно помогает. - person Theodore; 18.06.2020
comment
@Theodore Вы не сможете мутировать name с помощью get_name3(). Поскольку вы возвращаете копию, любая ваша мутация, такая как push_back, будет выполняться на копии, а не на исходном объекте name. Если вам нужен изменяемый доступ, используйте std::vector<std::string>& get_name(). Поскольку возвращаемая ссылка не является константой, вы сможете изменить объект, на который указывает ссылка. - person Guillaume Racicot; 18.06.2020
comment
Наконец-то мне удалось выполнить push_back для копии внутри функции get_name3(). Вот чего я не мог сделать. И я понимаю, что вы имеете в виду, изменяя объект, на который ссылаются. ВАУ, я понимаю гораздо больше, чем 24 часа назад! Большое спасибо, Гийом! - person Theodore; 18.06.2020

Функция-член имеет неявную this-ссылку.

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

Может ли эта функция-член также возвращать ссылку на некоторые постоянные данные, это может сильно коррелировать, но по-прежнему полностью зависит от программиста.

person Deduplicator    schedule 17.06.2020

Этот случай возвращает константную ссылку на vector<string>, и мы не можем изменить этот вектор. Но мы можем изменить vector<string> name в этой функции.

const vector<string> &get_name() { return name; } 

В этом случае верните копию vector<string>, и мы сможем изменить этот вектор, потому что это уже другой вектор. В этой функции мы не можем изменить vector<string> name.

vector<string> get_name() const { return name; } 
person Anton Shwarts    schedule 17.06.2020