C++: разница между амперсандом " & "и звездочкой" * " в объявлении функции/метода?


есть ли какая-то тонкая разница между ними:

void a1(float &b) {
    b=1;
};
a1(b);

и

void a1(float *b) {
    (*b)=1;
};
a1(&b);

?

Они оба делают то же самое (или так кажется из main ()), но первый явно короче, однако большая часть кода, который я вижу, использует вторую нотацию. Есть ли разница? Может быть, в случае, если это какой-то объект вместо поплавка?

7 59

7 ответов:

оба делают то же самое, но один использует ссылки и один использует указатели.

смотрите мой ответ здесь для полного списка всех различий.

да. Элемент * нотация говорит, что то, что передается в стеке, является указателем, т. е. адресом чего-то. Элемент & говорит, что это ссылка. Эффект похож, но не идентичен:

возьмем два случая:

   void examP(int* ip);
   void examR(int& i);

   int i;

если я называю examP, Я пишу

   examP(&i);

который принимает адрес элемента и передает его в стек. Если я позвоню examR,

   examR(i);

мне это не нужно; теперь компилятор "как-то" передает ссылка-что практически означает, что он получает и передает в адрес i. На стороне кода, то

   void examP(int* ip){
        *ip += 1;
   }

Я должен убедиться, что разыменовать указатель. ip += 1 делает что-то совсем другое.

   void examR(int& i){
        i += 1;
   }

всегда обновляет значение i.

чтобы больше думать, читайте на "вызов по ссылке "против" вызов по значению". Элемент & понятие дает вызов C++ по ссылке.

В первом примере со ссылками, вы знаете, что b не может быть NULL. С помощью примера указателя,b может быть нулевой указатель.

однако обратите внимание, что это и возможно передать нулевой объект через ссылку, но это неудобно, и вызванная процедура может предположить, что это ошибка:

a1(*(float *)NULL);

во втором примере caller должен префикс имени переменной С '&', чтобы передать адрес переменной.

Это может быть преимуществом-вызывающий не может случайно изменить переменную, передав ее в качестве ссылки, когда они думали, что они передают значение.

помимо синтаксического сахара, единственным реальным отличием является возможность для параметра функции, который является указателем, быть нулевым. Таким образом, версия указателя может быть более выразительной, если она правильно обрабатывает нулевой случай. Нулевой случай также может иметь какое-то особое значение. Ссылочная версия может работать только со значениями указанного типа без возможности null.

функционально в вашем примере обе версии делают то же самое.

первый имеет то преимущество, что он прозрачен на стороне вызова. Представьте, как это будет выглядеть для оператора:

cin >> &x;

и как это выглядит некрасиво для вызова своп

swap(&a, &b);

вы хотите поменять местами A и B. И это выглядит намного лучше, чем когда вы должны принять решения. Кстати, Бьярне Страуструп пишет, что основной причиной ссылок была прозрачность, которая была добавлено на стороне вызова-специально для операторов. Также посмотрите, как это уже не очевидно, является ли следующее

&a + 10

добавит 10 к содержимому a, вызывая оператор+ из него, или добавляет ли он 10 к временному указателю на a. добавьте это к невозможности, что вы не можете перегружать операторы только для встроенных операндов (например, указатель и целое число). Ссылки делают это кристально ясным.

указатели полезны, если вы хотите иметь возможность поставить "null":

a1(0);

затем в a1 метод может сравнить указатель с 0 и посмотреть, указывает ли указатель на какой-либо объект.

одна большая разница стоит отметить, что происходит снаружи, либо у вас есть:

a1(something);

или:

a1(&something);

мне нравится передавать аргументы по ссылке (всегда const one:)), когда они не изменяются в функции/методе (а затем вы также можете передавать автоматические/временные объекты внутри) и передавать их указателем для обозначения и предупреждения пользователя/читателя кода, вызывающего метод, что аргумент может и, вероятно, намеренно изменен внутри.