Причины проектирования поведения эталонных членов классов, передаваемых по константной ссылке
Предположим, чтобы иметь код
#include <iostream>
struct A{
int y;
int& x;
A():y(0),x(y){}
};
void f(int& x){
x++;
}
void g(const A& a){
f(a.x);
//f(a.y);
}
int main(){
A a;
g(a);
std::cout<<a.y<<std::endl;
}
внутри g() вызов f() для y недопустим, поскольку a передается с модификатором const, однако значение y можно изменить внутри g(), вызывая f для x;
С помощью указателей похожие вещи можно получить очень похожим образом.
struct B{
int* x;
}
а также
g(const B&){
*x++;
}
позволено. Это совершенно ясно: у нас есть константный указатель на неконстантный int. Но в предыдущем ссылочном примере, если ссылки являются объектом, почему в этом случае они ведут себя как указатели? Каковы политики дизайна под этим поведением?
3 ответа
Фактический язык в стандарте
8.3.2 Ссылки [dcl.ref]
1 - [...] [Примечание: ссылка может рассматриваться как имя объекта. —Конечная записка]
Так что, если ссылка - это имя объекта, а не сам объект, то имеет смысл, что вызывающая структура будет const
делает имя const
(что бессмысленно, поскольку ссылки не могут быть восстановлены), но не сам объект.
Мы также видим
6 - Если typedef, параметр шаблона типа или спецификатор decltype обозначает тип TR, который является ссылкой на тип T, попытка создать тип "lvalue ссылка на cv TR" создает тип "lvalue ссылка на Т ” [...]
Поскольку доступ члена к объекту cv создает значение cv lvalue, то же самое применяется, и квалификация cv прекращается.
если ссылки являются объектом
хотя ссылки не являются объектами - это ссылки на объекты.
Вы правы в том, что создание ссылки const само по себе не очень полезно: поскольку они не подлежат повторной настройке, их нельзя изменять как указатели в любом случае.
Фактически, было бы более полезно думать о ссылке как о константном указателе (не указателе на константу!) Со специальным синтаксисом.
Обратите внимание, что если вы хотите косвенное обращение, которое распространяет константность от рефери к референту (то есть, чтобы предотвратить f(a.x)
позвоните сюда), вы можете написать умную вещь в стиле указателя, чтобы сделать это.
Конкретный пример
struct A
{
int x;
int *p;
int &r;
A() : x(0), p(&x), r(x) {}
};
Сейчас в A a
:
a.x
изменчивый inta.p
является изменяемым указателем (таким образом, мы можем переустановить его) на изменяемое целое (мы можем изменить значение целого числа, на которое он указывает)- а также
a.r
ссылка на изменяемый int- обратите внимание, что, поскольку мы не можем изменить (переустановить) ссылки в любом случае, это не означает, что сама ссылка является постоянной или изменяемой
... но в const A b
:
b.x
постоянное целое числоb.p
постоянный указатель (поэтому мы не можем переустановить его) на изменяемый intb.r
ссылка на изменяемый int- обратите внимание, как константность применяется к элементу A (указателю или ссылке) и не распространяется на референт.
В C++ ссылки обычно реализуются указателями. (Я думаю, что sizeof
ссылка и указатель одинаковы).
Действительно, я обычно считаю ссылки указателями, но с другим синтаксисом.