Указатели
я с ними почти не работал и возник вопрос... т. к. они очень часто используются в С++, то хотелось бы знать в чем преимущество работы указателями над простой работой с объектами по ссылке, ну или просто с переменными?
Заранее спасибо!
тогда можно
{
1: ptr = &Obj1; break;
2: ptr = &Obj2; break;
3: ptr = &Obj3; break;
...
n: ptr = &Objn; break;
}
//и теперь можно делати тот самый блок операций используя *ptr вместо имени обьекта.
Это намного проще, чем
Всё же удобнее использовать функции, но ведь они тоже используют адреса и указатели:)
хотелось бы знать в чем преимущество работы указателями над простой работой с объектами по ссылке, ну или просто с переменными?
Главное преимущество работы с указателями - скорость. Например, надо передать в функцию какой-нибудь параметр, если передавать саму переменную, то на самом деле передастся копия этой переменной и все действия, производящиеся в функции, будут манипулировать именно копией, а не самой переменной. Это во-первых. А во-вторых, представь, что функцию надо передать объект очень большого размера, будет тратиться время на создание копии, а если это функция вызывается в цикле - заметное снижение производительности. Если же передается указатель - копия не создается, работа идет непосредственно с переменной. Быстро и классно :)
Правда существует опасность непреднамеренно изменить данные, но эту проблему можно решить с помощью квалификатора const.
Теперь, что касается ссылок. Язык C, как известно, является подмножеством C++. Понятие ссылки было введено в С++, в С были только указатели. По сути, ссылки и указатели это почти одно и то же. Передавая ссылку в функцию, передается именно ссылка, а не копия данных. Отличие только в синтаксисе. С ссылкой нужно работать точно так же, как непосредственно с переменной, для удобства программиста.
Не удобно - необходимо =)
1) Мы обязаны задать объект, на который ссылается ссылка, при инициализации ссылки (при объявлении переменной-ссылки или в конструкторе объекта, если переменная является членом класса).
2) "Перевести" ссылку на другой объект (сделать так, чтобы она ссылалась на другой объект) физически невозможно. Конструкция типа
int b;
int &int_ref = a;
.....
int_ref = b;
Будет работать не так, как ожидают некоторые - она не сделает так, что int_ref будет ссылаться на b, вместо этого она присвоит значение b переменной, на которую она ссылается, т. е. переменной a.
Посему, ссылки по своей сути всегда константны.
А вот указатель может быть как константным, так и модифицируемым, причем независимо от объекта, на который он указывает.
Т. е. для указателя возможны 4 варианта:
const int *int_ptr; // Модифицируемый указатель на константный объект
int * const int_ptr; // Константный указатель на модифицируемый объект
const int * const int_ptr; // Константный указатель на константный объект
А вот для ссылки возможны только 2 варианта:
const int &int_ref; // Ссылка на константный объект
Запись типа
Не имеет смысла по вышеуказанным причинам. Такой код либо не компилируется (выдается ошибка), либо, как минимум, warning.
Из-за того, что мы обязаны инициализировать ссылку при ее объявлении, мы не всегда можем использовать ссылки. Например, если ссылку нужно проинициализировать разными значениями в зависимости от условия, код
int b;
...
int &int_ref; // Ошибка: мы обязаны инициализировать ссылку
if (условие)
int_ref = a;
else
int_ref = b;
Не будет работать по двум причинам - переменная-ссылка не инициализирована при объявлении (выдается сообщение об ошибке) и запись int_ref = a будет выполнять присваивание вместо "перевода" ссылки. В таком случае без указателей не обойтись.
Преимущество указателей перед передачей параметра по значению такое же, как преимущество ссылки перед передачей по значению.
{
// Содержимое класса
};
void SomeFunction(A a);
void SomeFunc2()
{
A a;
SomeFunction(a);
}
1. При таком вызове производится создание копии объекта, что может быть времяемким, а то и вовсе невозможным (некоторые объекты бывают принципиально некопируемыми по своей логике; другие объекты могут выполнять нетривиальное копирование, в результате чего копия может не совпадать с оригиналом - все зависит от копи-конструктора).
2. В функцию передается именно копия объекта, а не исходный объект. Тем самым, функция может менять содержимое, но менять она будет копию, а не исходный объект.
А вот если функцию объявить подобным образом:
или
void SomeFunction(A *a)
1. Не тратится время на создание копии объекта.
2. Передаваться будет ссылка (указатель) на исходный объект, в результате чего вызываемая функция может модифицировать его.
Для запрета модификации можно, к примеру, объявить параметр как ссылку на константный объект (A const &a) или указатель на константный объект (A const *a).
З.Ы. Когда начинал учить СИ еще в прошлом веке тоже не понимал нах.. эти указатели нужны, но когда доехал понял что это просто крутая штука и без нее никуда!
Особенно cheburator и flat
кажется понял.
Теперь я понял, почему в VB так мало работают с указателями. Там объекты в функции можно передавать только по ссылке и ссылки причем не требуют сразу же экземпляр класса, как тут... - там немного упрощено для написания
еще раз спасибо!
int *px1 = x;
int *px2 = &x[0]; // px2 == px1
int t1 = px2[2];
int t2 = *(px1 + 2); // t1 == t1
Из-за того, что мы обязаны инициализировать ссылку при ее объявлении, мы не всегда можем использовать ссылки. Например, если ссылку нужно проинициализировать разными значениями в зависимости от условия, код
int b;
...
int &int_ref; // Ошибка: мы обязаны инициализировать ссылку
if (условие)
int_ref = a;
else
int_ref = b;
Не будет работать по двум причинам - переменная-ссылка не инициализирована при объявлении (выдается сообщение об ошибке) и запись int_ref = a будет выполнять присваивание вместо "перевода" ссылки. В таком случае без указателей не обойтись.
А разве нельзя было использовать тринарный оператор?
Так тоже делается и очень хорошо работает. Но называется "условное присваивание"