разница между указателем и ссылочным параметром?
это то же самое:
int foo(bar* p) {
return p->someInt();
}
и
int foo(bar& r) {
return r.someInt();
}
игнорировать потенциал нулевого указателя. Являются ли эти две функции функционально идентичными независимо от того, если someInt()
является виртуальным или если они передаются bar
или подкласс bar
?
делает ли этот срез что-нибудь:
bar& ref = *ptr_to_bar;
8 ответов
ссылки на C++ намеренно не указаны в стандарте, который будет реализован с помощью указателей. Ссылка больше похожа на "синоним" переменной, чем на указатель на нее. Эта семантика открывает некоторые возможные оптимизации для компилятора, когда можно понять, что указатель в некоторых ситуациях будет излишним.
еще несколько различий:
- вы не можете назначить NULL ссылке. Это принципиальное различие и главная причина ты предпочитаете один над другой.
- когда вы берете адрес указатель, вы получаете адрес указатель. Когда вы берете адрес ссылки, вы получаете адрес переменной упоминаемый.
- вы не можете переназначить ссылку. Как только он инициализирован, он указывает на один и тот же объект на всю свою жизнь.
игнорирование каждого синтаксического сахара и возможностей, которые могут быть сделаны с одним, а не с другим, и разница между указателями и ссылками, объясненными в других ответах (на другие вопросы) ... Да, эти двое функционально абсолютно одинаковы! Оба вызова функции и оба одинаково хорошо обрабатывают виртуальные функции.
и нет, ваша линия не нарезать. Это просто привязка берется непосредственно к объекту, на который указывает указатель.
некоторые вопросы о том, почему вы хотите использовать один над другим:
- разницу между указателем и ссылкой
- есть ли какие-либо преимущества передачи указателем по ссылке?
- указатель и ссылка
вместо того, чтобы пытаться придумать различия сам, я делегирую вас тем, если вы хотите знать.
Ссылка-это постоянный указатель, т. е. вы не можете изменить ссылку для ссылки на другой объект. При изменении значения объекта ссылки изменяется.
Например:
int j = 10;
int &i = j;
int l = 20;
i = l; // Now value of j = 20
int *k = &j;
k = &l; // Value of j is still 10
Да, они функционально идентичны. Поскольку ссылка потребует, чтобы вы установили ее на объект перед его использованием, вам не придется иметь дело с нулевыми указателями или указателями на недопустимую память.
также важно увидеть семантическую разницу:
- используйте ссылку, когда вы фактически передадите объект нормально, но он настолько велик, что имеет смысл передать ссылку на объект, а не делать копию (если вы не изменяете объект то есть).
- используйте указатель, когда вы хотите иметь дело с адресом памяти, а не с объектом.
Я давно не использовал C++, поэтому я даже не собираюсь пытаться действительно ответить на ваш вопрос (Извините); однако Эрик Липперт только что опубликовал отличная статья о указателях / ссылках, на которые я решил указать вам.
Не уверен, что кто-то ответил на ваш 2-й вопрос, скрытый внизу о нарезке... нет, это не вызовет порезов.
нарезка - это когда производный объект присваивается (копируется) объекту базового класса-специализация производного класса "отрезается". Обратите внимание, что я сказал объект копируется, мы говорим не о копируемых/назначаемых указателях, а о самих объектах.
в вашем примере этого не происходит. Вы просто отсылаете указатель на объект Bar (в результате чего объект Bar) используется в качестве rvalue в инициализации ссылки. Не уверен, что правильно понял терминологию...
как все уже упоминали, в реализации ссылки и указатели в основном одинаковы. Есть некоторые незначительные предостережения:
вы не можете присвоить NULL ссылке (Шуш упомянул об этом): поскольку нет "неопределенная "или" недопустимая " ссылка значение.
вы можете пройти временную переменная как const ссылка, но это не законно, чтобы передать указатель к временному.
например, вот так:
class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{
a.DoSomething();
}
void bar( )
{
foo( Thingy(1,2) );
}
но большинство компиляторов будут жаловаться на
void foo2( Thingy * a);
void bar2()
{
foo( &Thingy(1,2) );
}
- взятие адреса переменной для получения указателя заставляет компилятор сохранять ее в памяти. Назначение ссылки на локальную переменную просто создает синоним; в некоторых случаях это может позволить компилятору сохранить данные в регистре и избежать load-hit-store. Однако это относится только к локальным переменным -- один раз что-то передается как параметр по ссылке, не избежать сохранения его в стек.
void foo()
{
int a = 5;
// this may be slightly more efficient
int &b = a;
printf( "%d", ++b );
// than this
int *c = &a;
printf( "%d", ++(*c) );
}
аналогично _ _ restrict keyword не может применяться к ссылкам, только указатели.
вы не можете делать арифметику указателя со ссылками, поэтому, если у вас есть указатель на массив, то следующий элемент в массиве может быть через p+1, Ссылка только когда-либо указывает на одну вещь в его вся жизнь.
функции, очевидно, не "одинаковы", но в отношении виртуального поведения они будут вести себя аналогично. Что касается нарезки, это происходит только тогда, когда вы имеете дело с значениями, А не ссылками или указателями.