Передача объекта по ссылке в С++

Обычный способ передать переменную по ссылке в С++ (также C) выглядит следующим образом:

void _someFunction(dataType *name){ // dataType e.g int,char,float etc.
/****
definition
*/
}

int main(){
    dataType v;
    _somefunction(&v);  //address of variable v being passed
    return 0;
}

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

// this
#include <iostream>
using namespace std;

class CDummy {
  public:
    int isitme (CDummy& param);     //why not (CDummy* param);
};

int CDummy::isitme (CDummy& param)
{
  if (&param == this) return true;
  else return false;
}

int main () {
  CDummy a;
  CDummy* b = &a;
  if ( b->isitme(a) )               //why not isitme(&a)
    cout << "yes, &a is b";
  return 0;
}

У меня проблема с пониманием, почему это специальное обращение с классом. Даже такие структуры, которые почти как класс, не используются таким образом. Имя объекта рассматривается как адрес, как в случае массивов?

Ответы

Ответ 1

Кажется, что вас сбивает с толку тот факт, что функции, объявленные как pass-by-reference (используя &), не вызывается с использованием фактических адресов, т.е. &a.

Простой ответ заключается в том, что объявление функции в качестве передачи по ссылке:

void foo(int& x);

- это все, что нам нужно. Затем он автоматически передается по ссылке.

Теперь вы вызываете эту функцию следующим образом:

int y = 5;
foo(y);

и y будут переданы по ссылке.

Вы также можете сделать это так (но почему бы вам?) Мантра: используйте ссылки, когда это возможно, указатели при необходимости):

#include <iostream>
using namespace std;

class CDummy {
public:
    int isitme (CDummy* param);
};


int CDummy::isitme (CDummy* param)
{
    if (param == this) return true;
    else return false;
}

int main () {
    CDummy a;
    CDummy* b = &a;             // assigning address of a to b
    if ( b->isitme(&a) )        // Called with &a (address of a) instead of a
        cout << "yes, &a is b";
    return 0;
}

Вывод:

yes, &a is b

Ответ 2

Ссылка - это действительно указатель с достаточным количеством сахара, чтобы сделать его приятным вкусом...;)

Но он также использует другой синтаксис для указателей, что упрощает использование ссылок, чем указателей. Из-за этого нам не нужно & при вызове функции, которая принимает указатель - компилятор имеет дело с этим для вас. И вам не нужно *, чтобы получить содержание ссылки.

Чтобы вызвать ссылку, псевдоним является довольно точным описанием - это "другое имя для одной и той же вещи". Поэтому, когда a передается как ссылка, мы действительно передаем a, а не копию a - это делается (внутренне), передавая адрес a, но вам не нужно беспокоиться о том, как это работает [если вы не пишете собственный компилятор, но тогда есть много других интересных вещей, которые вам нужно знать при написании собственного компилятора, что вам не нужно беспокоиться о том, когда вы просто программируете].

Обратите внимание, что ссылки работают одинаково для типов int или class.

Ответ 3

Передача по ссылке в приведенном выше случае - это просто alias для фактического объекта.

Вы будете ссылаться на фактический объект только с другим именем.

Есть много преимуществ, которые references предлагают по сравнению с pointer references.

Ответ 4

Одна вещь, которую я должен добавить, это то, что в C нет ссылки.

Во-вторых, это соглашение о синтаксисе языка. & Амп; - это оператор адреса, но он также означает ссылку - все зависит от случая usa

Если вместо этого было какое-то ключевое слово "reference", и вы могли написать

int CDummy::isitme (reference CDummy param)

но это С++, и мы должны признать его преимуществами и недостатками...

Ответ 5

Хорошо, похоже, что вы путаете pass-by-reference с pass-by-value. Кроме того, C и С++ - разные языки. C не поддерживает передачу по ссылке.

Вот два примера перехода С++ по значению:

// ex.1
int add(int a, int b)
{
    return a + b;
}

// ex.2
void add(int a, int b, int *result)
{
    *result = a + b;
}

void main()
{
    int result = 0;

    // ex.1
    result = add(2,2); // result will be 4 after call

    // ex.2
    add(2,3,&result); // result will be 5 after call
}

Когда вызывается ex.1, константы 2 и 2 передаются в функцию, делая локальные копии их в стеке. Когда функция возвращается, стек отбрасывается, и все, что передается функции в стеке, эффективно исчезает.

То же самое происходит в ex.2, за исключением этого времени, указатель на переменную int также передается в стек. Функция использует этот указатель (который является просто адресом памяти) для разыменования и изменения значения на этом адресе памяти, чтобы "вернуть" результат. Поскольку функции требуется адрес памяти в качестве параметра, тогда мы должны предоставить ее один, который мы будем использовать с помощью оператора & "address-of" для переменной result.

Вот два примера С++ для ссылки:

// ex.3
int add(int &a, int &b)
{
    return a+b;
}

// ex.4
void add(int &a, int &b, int &result)
{
    result = a + b;
}

void main()
{
    int result = 0;

    // ex.3
    result = add(2,2); // result = 2 after call
    // ex.4
    add(2,3,result); // result = 5 after call
}

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

Сначала давайте проясним, как работает перекрестная ссылка. В pass-by-reference, как правило, реализация компилятора будет использовать переменную "указатель" в конечном исполняемом файле для доступа к ссылочной переменной (или, похоже, это консенсус), но это не обязательно должно быть правдой. Технически компилятор может просто напрямую заменить указанный адрес переменной памяти, и я подозреваю, что это более верно, чем обычно полагают. Таким образом, при использовании ссылки он может фактически создать более эффективный исполняемый файл, пусть даже немного.

Далее, очевидно, что метод, вызываемый при использовании pass-by-reference, не отличается от значения pass-by-value, и эффект заключается в том, что у вас есть прямой доступ к исходным переменным внутри функции. Это результат инкапсуляции, скрывая детали реализации от вызывающего. Недостатком является то, что вы не можете изменять переданные параметры без изменения исходных переменных вне функции. В тех функциях, в которых вы хотите улучшить производительность, не имея необходимости копировать большие объекты, но вы не хотите изменять исходный объект, а затем префикс ссылочных параметров const.

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

Надеюсь, я все охватил, и все это было понятно.