Что делает '&', делают в объявлении C++?

Я - парень C, и я пытаюсь понять некоторый код C++. У меня есть следующее объявление функции:

int foo(const string &myname) {
  cout << "called foo for: " << myname << endl;
  return 0;
}

Как делает функциональную подпись, отличаются от эквивалентного C:

int foo(const char *myname)

Есть ли различие между использованием string *myname по сравнению с string &myname? Между чем различие & в C++ и * в C для указания на указатели?

Так же:

const string &GetMethodName() { ... }

Что & выполнение здесь? Есть ли некоторый веб-сайт, который объясняет как & используется по-другому в C по сравнению с C++?

39
задан Makoto 18 October 2013 в 04:43
поделиться

7 ответов

Знак "&" обозначает ссылку вместо указателя на объект (в вашем случае постоянную ссылку).

Преимущество такой функции, как

foo(string const& myname) 

перед

foo(string const* myname)

, заключается в том, что в первом случае вам гарантируется, что myname не равно нулю, поскольку C ++ не допускает NULL-ссылки. Поскольку вы передаете по ссылке, объект не копируется, как если бы вы передавали указатель.

Ваш второй пример:

const string &GetMethodName() { ... }

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

class A
{
  public:
  int bar() const {return someValue;}
  //Big, expensive to copy class
}

class B
{
public:
 A const& getA() { return mA;}
private:
 A mA;
}
void someFunction()
{
 B b = B();
 //Access A, ability to call const functions on A
 //No need to check for null, since reference is guaranteed to be valid.
 int value = b.getA().bar(); 
}

Вы, конечно, должны быть осторожны, чтобы не вернуть недопустимые ссылки. Компиляторы с радостью скомпилируют следующее (в зависимости от вашего уровня предупреждений и того, как вы обрабатываете предупреждения)

int const& foo() 
{
 int a;

 //This is very bad, returning reference to something on the stack. This will
 //crash at runtime.
 return a; 
}

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

33
ответ дан 27 November 2019 в 02:42
поделиться

Здесь & не используется в качестве оператора. Как часть объявления функции или переменной & обозначает ссылку. В C ++ FAQ Lite есть довольно изящная глава со ссылками .

17
ответ дан 27 November 2019 в 02:42
поделиться
#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
            int number;
            int result;
            number=5;
            cout << "The value of the variable number before calling the function : " << number << endl;
            result=add(&number);
            cout << "The value of the variable number after the function is returned : " << number << endl;
            cout << "The value of result : " << result << endl;
            return(0);
}

int add(int &p)
{
            *p=*p+100;
            return(*p);
}

Это недопустимый код по нескольким причинам. Выполнение его через g ++ дает:

crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’

Допустимая версия кода гласит:

#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
            int number;
            int result;
            number=5;
            cout << "The value of the variable number before calling the function : " << number << endl;
            result=add(number);
            cout << "The value of the variable number after the function is returned : " << number << endl;
            cout << "The value of result : " << result << endl;
            return(0);
}

int add(int &p)
{
            p=p+100;
            return p;
}

Здесь происходит то, что вы передаете переменную «как есть» в свою функцию. Это примерно эквивалентно:

int add(int *p)
{
      *p=*p+100;
      return *p;
}

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

int add(int &p)
{
            *p=*p+100;
            return p;
}

недействителен.

Если вы должны использовать указатель на ссылку, это должно быть сделано явно:

int add(int &p)
{
                    int* i = &p;
            i=i+100L;
            return *i;
}

Что при тестовом запуске дает (как и ожидалось) нежелательный вывод :

The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792
1
ответ дан 27 November 2019 в 02:42
поделиться

Один из способов взглянуть на оператор & (ссылка) в С ++ - это просто синтаксический сахар для указателя. Например, следующие примерно эквивалентны:

void foo(int &x)
{
    x = x + 1;
}

void foo(int *x)
{
    *x = *x + 1;
}

Более полезно, когда вы имеете дело с классом, так что ваши методы меняются с x-> bar () на x.bar ().

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

1
ответ дан 27 November 2019 в 02:42
поделиться

строка * и строка & различаются несколькими способами. Прежде всего, указатель указывает на адресное расположение данных. Ссылка указывает на данные. Если бы у вас была следующая функция:

int foo(string *param1);

, вам нужно было бы проверить объявление функции, чтобы убедиться, что param1 указывает на допустимое местоположение. Для сравнения:

int foo(string &param1);

Здесь ответственность за правильность указанных данных лежит на вызывающей стороне. Вы не можете передать значение "NULL", например, во вторую функцию выше.

Что касается вашего второго вопроса, о том, что возвращаемые значения метода являются ссылкой, рассмотрите следующие три функции:

string &foo();
string *foo();
string foo();

В В первом случае вы вернете ссылку на данные. Если бы ваше объявление функции выглядело так:

string &foo()
{
    string localString = "Hello!";
    return localString;
}

Вы, вероятно, получили бы некоторые ошибки компилятора, поскольку вы возвращаете ссылку на строку, которая была инициализирована в стеке для этой функции. При возврате функции это местоположение данных больше не является действительным. Как правило, вы хотите вернуть ссылку на член класса или что-то в этом роде.

Вторая функция выше возвращает указатель в реальной памяти, поэтому он останется прежним. Однако вам придется проверять NULL-указатели.

Наконец, в третьем случае возвращаемые данные будут скопированы в возвращаемое значение для вызывающего. Итак, если ваша функция выглядит так:

string foo()
{
    string localString = "Hello!";
    return localString;
}

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

вы захотите вернуть ссылку на член класса или что-то в этом роде.

Вторая функция выше возвращает указатель в реальной памяти, поэтому он останется прежним. Однако вам придется проверять NULL-указатели.

Наконец, в третьем случае возвращаемые данные будут скопированы в возвращаемое значение для вызывающего. Итак, если ваша функция выглядит так:

string foo()
{
    string localString = "Hello!";
    return localString;
}

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

вы захотите вернуть ссылку на член класса или что-то в этом роде.

Вторая функция выше возвращает указатель в реальной памяти, поэтому он останется прежним. Однако вам придется проверять NULL-указатели.

Наконец, в третьем случае возвращенные данные будут скопированы в возвращаемое значение для вызывающего. Итак, если ваша функция выглядит так:

string foo()
{
    string localString = "Hello!";
    return localString;
}

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

8
ответ дан 27 November 2019 в 02:42
поделиться

Я думаю, что вы правы, объединившись в единую библиотеку.

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

Интересный вопрос! Посмотрим, что думают другие :)

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

Интересный вопрос! Посмотрим, что думают другие :)

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

Интересный вопрос! Посмотрим, что думают другие :)

а const char * необходимо разыменовать, чтобы указать на данные.

Есть ли разница между использованием строки * myname и строки & myname?

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

int add_ptr(int *x, int* y)
{
    return *x + *y;
}
int add_ref(int &x, int &y)
{
    return x + y;
}

, которые делают то же самое. Единственное отличие в этом случае состоит в том, что вам не нужно разыменовать x и y , поскольку они относятся непосредственно к переданным переменным.

const string &GetMethodName() { ... }

Что здесь делает &? Есть ли какой-нибудь веб-сайт, на котором объясняется, как & по-разному используется в C и C ++?

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

1
ответ дан 27 November 2019 в 02:42
поделиться

В этом контексте & заставляет функцию принимать имя строки по ссылке. Разница между ссылками и указателями:

  • Когда вы берете ссылку на переменную, эта ссылка является переменной, на которую вы ссылаетесь. Вам не нужно разыменовать ее или что-то еще, работа со ссылкой семантически эквивалентна работе с самой переменной, на которую указывает ссылка.
  • NULL не является допустимым значением для ссылки и приведет к ошибке компилятора. Итак, как правило, если вы хотите использовать выходной параметр (или указатель / ссылку в целом) в функции C ++ и должна быть разрешена передача нулевого значения этому параметру, тогда используйте указатель (или, предпочтительно, интеллектуальный указатель). Если передача нулевого значения не имеет смысла для этой функции, используйте ссылку.
  • Вы не можете «повторно разместить» ссылку. Хотя значение указателя можно изменить, чтобы указать на что-то еще, ссылка не имеет аналогичных функций. Как только вы берете переменную по ссылке, вы фактически имеете дело с этой переменной напрямую. Точно так же, как вы не можете изменить значение a , написав b = 4; . Значение ссылки - это значение того, на что она ссылается.
0
ответ дан 27 November 2019 в 02:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: