Указатели и ссылки - PullRequest
       3

Указатели и ссылки

1 голос
/ 13 февраля 2012

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

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

Итак, по ссылке:

#include <iostream>

class student{
public:
    int semesterHours;
    float gpa;
};

void defRefS( student &refS );
void defPointerS( student *Ps );
void defValueS( student cS );

int main()
{
    student s;
    defRefS(s); //Here,
    std::cout << "\nBack in main we have " << s.semesterHours << " hours";
    std::cout << "\nBack in main the GPA is: " << s.gpa;


    student *Ps = &s;
    defPointerS(&s); //And here is where I get confused
    std::cout << "\nBack in main we have " << s.semesterHours << " hours";
    std::cout << "\nBack in main the GPA is: " << s.gpa;

    defValueS(s);
    std::cout << "\nBack in main object S has: " << s.semesterHours << " hours";
    std::cout << "\nBack in main object S has: " << s.gpa << " GPA\n\n";

}

void defRefS( student &refS ) //Passing by reference to object
{
    refS.gpa = 4.0;
    refS.semesterHours = 12;
    std::cout << "\n------------- Reference Function ------------";
    std::cout << "\n\nObject S has: " << refS.semesterHours << " hours";
    std::cout << "\nObject S has: " << refS.gpa << " GPA";
}

void defPointerS( student *Ps ) //Passing a pointer to the object
{
    Ps->gpa = 5.0;
    Ps->semesterHours = 14;
    std::cout << "\n\n------------- Pointer Function ---------------";
    std::cout << "\n\nNow object S has: " << Ps->semesterHours << " hours";
    std::cout << "\nNow object S has: " << Ps->gpa << " GPA";
}

void defValueS( student cS ) //Passing the object by value
{
    cS.gpa = 100;
    cS.semesterHours = 50;
    std::cout << "\n\n------------- Value Function ------------------";
    std::cout << "\n\nObject S has: " << cS.semesterHours << " hours";
    std::cout << "\nObject S has: " << cS.gpa << " GPA";
}

Передача по ссылке, по существу, позволяет обозначениям быть похожими, поскольку, я полагаю, во всех отношениях refS является s объектом. Таким образом, это приводит к простому способу манипулирования объектом с помощью функции.

Передача указателя достаточно проста для понимания. Это просто указатель на объект. Хотя как насчет этого в приведенном выше коде:

void defRefS( student &refS );
void defPointerS( student *Ps );
void defValueS( student cS );

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

defRefS(s); //Here,
defPointerS(&s); //And here is where I get confused
defValueS(s);

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

Функция defPointerS определена для приема указателей; Я отправляю ей адреса?

Ответы [ 6 ]

2 голосов
/ 13 февраля 2012

Вы путаетесь между двумя использованиями амперсанда (&). В одном случае это оператор, а в другом - часть типа объявления.

int x = 5;
int* y = &x; // (1) Here it's an operator
int& z = x;  // (2) Here it's part of the type of y

В строке (1) выше мы объявляем и определяем переменную с именем y типа pointer to int. Это означает, что переменная y должна содержать адрес переменной типа int. Чтобы получить адрес переменной, вы используете & в качестве оператора. Таким образом, &x является адресом x, и мы храним его в указателе. y теперь указатель на x.

В строке (2) мы определяем переменную с именем z, которая имеет тип reference to int. Поскольку мы привязываем x к этой ссылке, это означает, что мы можем использовать z в качестве другого имени для x. Изменение z изменит x (а также значение, на которое указывает y!).

Поэтому, когда у вас есть функция, которая принимает указатель, например, void func(int* p), вам нужно передать ей адрес типа int. Для этого вам нужно либо передать указатель напрямую, либо взять адрес int:

int x = 5;
func(&x);

Если у вас есть функция, которая принимает ссылку, например, void func(int& r), вам нужно только передать ей int. Ссылка будет относиться к тому же int.

int x = 5;
func(x);

Их можно использовать аналогичным образом: передать аргумент функции, чтобы она могла изменить его, или избежать копирования. Тем не менее, аргумент указателя также позволяет передавать нулевой указатель в функцию. Это не работает со ссылкой, потому что ссылка всегда должна быть привязана к чему-либо. Кроме того, после привязки ссылка не может быть восстановлена ​​на другой объект.

Ссылки, как правило, гораздо удобнее и не полагаются на манипуляции с указателями в стиле C. В C ++ вы обычно хотите использовать ссылку, когда можете, и указатель, если необходимо. Подробнее см. FAQ по C ++ .

2 голосов
/ 13 февраля 2012

Полагаю, вы только начинаете работать с C ++.Не беспокойтесь о куче, это концепция более низкого уровня, о которой вы узнаете позже.Если вы действительно заинтересованы, оператор new и malloc выделяют память в куче (new фактически также вызывает конструктор объекта, давая вам динамический объект).Вы можете думать об этом как о большом пространстве, куда вы можете поместить вещи, которые вы хотите позже).

О указателях и ссылках, они большую часть времени взаимозаменяемы (как вы выяснили).Это зависит только от того, как вы хотите структурировать свой код.

В C ++ указатели есть везде, и люди обычно передают указатели, а не передаются по ссылке.Одна из причин, по которой указатели используются чаще, заключается в том, как работает динамическое выделение памяти (оператор new или malloc) - он возвращает указатель - и вы делаете это много.Поэтому, как правило, вы выполняете работу над объектом с указанным вами указателем.

Редкие случаи, когда вам абсолютно необходимо использовать ссылки, это в конструкторе копирования или в определении операторов.

IВозможно, пропустили несколько случаев, но это суть.

1 голос
/ 13 февраля 2012

В чем преимущество использования одного над другим?

Хорошая причина использовать ссылку для передачи входного параметра для функции: ссылка никогда не может быть NULL, поэтому вы неНе нужно проверять, указывает ли указатель куда-либо.

Хорошая причина использовать указатель для передачи входного параметра для функции: вы можете использовать арифметику указателей, чтобы вы могли передавать массивы (что не рекомендуется в c ++).Так что лучше придерживаться ссылок в большинстве случаев.

Если вы передаете по ссылке, разве вы не должны передавать адрес объекта? - Нет, вы передаете объект как есть.Параметр рядом с амперсандом означает, что параметр получает ссылку на объект без копирования.

Функция defPointerS определена для приема указателей;Я отправляю ему адреса? - оператор «&» при применении к r-значению выдает указатель на объект.

1 голос
/ 13 февраля 2012

Когда вы используете символ & в определении функции / типа (как в void defRefS( student &refS ); или student &refS) - вы определяете ссылку.Значением будет ссылка.

Когда вы используете один и тот же оператор (то есть: тот же символ &) для объекта (переменной), вы получаете адрес этого конкретного объекта (как вstudent *Ps = &s; или defPointerS(&s);).Значение будет указателем.

Все еще в замешательстве?Тогда не читайте следующее предложение.Оператор & также является побитовым И, когда в операторе, например, 0x1 & 0xFF, возвращает 1. Возвращаемое значение будет целым числом в размере самого большого целого числа в операторе.

0 голосов
/ 13 февраля 2012

Для начала см. В чем различия между переменной указателя и ссылочной переменной в C ++? .

При передаче переменной по ссылке вы можете думать, что она неявно берет адрес, поэтому вам не нужно писать &, но она все равно делает это за вас (поэтому вы получите ошибку, если передать константу, например, «5» для параметра ссылки). Он также неявно разыменовывает его внутри функции, поэтому вам не нужно писать «*».

"Функция defPointerS определена для приема указателей; я отправляю ей адреса?" Указатель - это адрес (или, точнее, переменная, в которой хранится значение адреса памяти).

"Значит, эти функции могут только передавать ссылку, указатель и значения объектов в этот конкретный класс?" Эти типы указывают, что если вы попытаетесь передать экземпляр другого класса этой функции, вы получите ошибку компилятора. Однако C ++ не обеспечивает строгого обеспечения безопасности типов, и вы можете обойти это и заставить его передавать указатели на другие типы объектов с помощью reinterpret_cast. В большинстве случаев это не будет работать.

0 голосов
/ 13 февраля 2012

Если у вас есть переменная student s; и вы хотите передать ее в функцию f, которая принимает аргумент типа student (передача по значению) или student& (передача по ссылке), вы просто вызываете f(s) , Если вы передаете s по значению, то создается копия s, и вы работаете с копией s в теле функции. Если вы передаете его по ссылке, вы работаете непосредственно с объектом s. Ссылка не может быть NULL, что является большим преимуществом во многих ситуациях.

Когда тип этого аргумента student* (также передается по ссылке), вы вызываете f(&s), так как указатель должен быть инициализирован с адресом, на который он будет указывать.

Вы также должны проверить: Указатель против ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...