Глава 8
Вверх
В листинге 9.11 проблема создания излишних временных копий решена.
Сокращается число обращений к конструктору и деструктору класса, программа
работает более эффективно. Здесь использовался постоянный указатель
на постоянный объект, что предотвращало возможность изменения объекта
собственной функцией. Но определенная громоздкость синтаксиса, свойственная
для указателей остается.
Поскольку известно что объект никогда не бывает нулевым, внутреннее
содержание функции упростилось бы , если бы ей вместо указателя,
передавалась ссылка.
Это подтверждается следующей программой.
Передача ссылок объектам.
//Listing 9.11
// Passing pointers to objects
class SimpleCat
{
int GetAge() const {
private:
SimpleCat::SimpleCat()
{
SimpleCat::SimpleCat(SimpleCat&)
{
SimpleCat::~SimpleCat()
{
const SimpleCat & const FunctionTwo
int main()
{
cout << "Frisky is " ;
int age = 5;
cout << "Frisky is " ;
cout << "Calling FunctionTwo...\n";
cout << "Frisky is " ;
// functionTwo, передает ссылку постоянному объекту
const SimpleCat & const FunctionTwo
Результат:
5.Calling FunctionTwo...
Анализ:
Результат работы программы тот же что и 9.11. Единственно несколько
изменилась функция FunctionTwo() которая принимает и возвращает
теперь ссылки на постоянный объект.
Как видим работа со ссылками оказывается эффективнее чем работа с
указателями, хотя при этом достигается та же экономия средств и эффективность
выполнения. Кроме того обеспечивается надежность за счет привлечения
компилятора для поиска возможных ошибок.
Вверх
Опытные программисты безоговорочно отдают предпочтение ссылкам, а не
указателям.
Ссылки проще использовать и они позволяют скрыть информацию, как было показано
в предыдущем примере.
Ссылки нельзя переназначить. Поэтому если необходимо сначала указывать на один
объект, а затем на другой то придется использовать указатель. Ссылки не могут
быть нулевыми, поэтому если существует вероятность того что рассматриваемый
объект может стать нулевым, использовать ссылку нельзя. В этом случае
необходим указатель.
Оператор new например. Если оператор new не может выделить память для нового
объекта, то он возвратит нулевой указатель. А поскольку ссылка не может быть
нулевой, то инициализировать ссылку на эту область памяти нельзя до тех пор
пока не будет установлено что она не нулевая.
В этом примере объявлен указатель pInt на переменную типа int , который
инициализируется областью памяти, возвращаемой оператором new.
Адрес этой области памяти (в указателе pInt) проверяется, и если он не равен
значению null, то этим результатом инициализируется ссылка rInt. Следовательно
ссылка rInt становится псевдонимом для гарантированно существующей переменной
типа int, возвращаемой оператором new.
Вверх
Вполне допустимо объявить в списке параметров функции одновременно и
указатели, и ссылки и объекты передаваемые в виде значений.
-.-.-.-.-.-.-.-.-.-.
Вверх
Научившись передавать ссылки на объекты как аргументы , программисты порой
теряют осторожность. Не стоит забывать что все хорошо в меру.
Помните что ссылка всегда служит псевдонимом некоторого объекта.
При передаче ссылки в функцию, или из нее не лишне задаться вопросом
"Что представляет собой объект, псевдонимом которого предстоит
воспользоваться, и будет ли он существовать в момент его применения?"
В следующей программе показан пример возможной ошибки, когда функция
возвращает ссылку на объект, которого уже не существует.
Возвращение ссылки на несуществующий объект.
// Listing 9.13
// Returning a reference to an object
// which no longer exists
class SimpleCat
{
SimpleCat::SimpleCat(int age, int weight)
{
SimpleCat &TheFunction();
int main()
{
SimpleCat &TheFunction()
{
Результат:
Программа не компилируется!
В стр 7-17 объявляется класс SimpleCat.
В стр 29 инициализируется ссылка на объект класса SimpleCat
с использованием результатов вызова функции theFunction(), объявленной в
стр 25.
Согласно объявлению функция возвращает ссылку на объект класса SimpleCat.
SimpleCat &TheFunction()
В теле функции theFunction() объявляется локальный объект типа SimpleCat
и инициализируется значение его возраста и веса.Затем этот объект
возвращается по ссылке.
Некоторые компиляторы обладают достаточным интеллектом, чтобы распознать
эту ошибку, и не позволяют запустить программу на исполнение. Другие же
(сразу видно кто настоящий друг)разрешают выполнить эту программу с
непредсказуемыми последствиями.
По возвращении из функции theFunction() локальный объект Frisky будет
разрушен и возвращаемая этой функцией ссылка останется псевдонимом
несуществующего объекта, а это очень нехорошо.
Если объект создается внутри функции, как в данном примере, а затем
возвращаемым значением функции является ссылка на этот объект, то когда
функция заканчивает свою работу, созданный в ней объект уничтожается и
на что спрашивается теперь указывает ссылка?На несуществующий объект!?
А это уж нонсенс!
Назад |
Начало урока |
Вверх |
Вперед
Ссылки в качестве альтернативы.
#include <iostream>
using namespace std;
SimpleCat();
SimpleCat(SimpleCat&);
~SimpleCat();
void SetAge(int age) {
int itsAge;
cout << "Simple Cat Constructor...\n";
itsAge = 1;
cout << "Simple Cat Copy Constructor...\n";
cout << "Simple Cat Destructor...\n";
(const SimpleCat & const theCat);
cout << "Making a cat...\n";
SimpleCat Frisky;
cout << Frisky.GetAge();
cout << " years old\n";
Frisky.SetAge(age);
cout << Frisky.GetAge();
cout << " years old\n";
FunctionTwo(Frisky);
cout << Frisky.GetAge();
cout << " years old\n";
return 0;
(const SimpleCat & const theCat)
{
cout << "Function Two. Returning...\n";
cout << "Frisky is now " << theCat.GetAge();
cout << " years old \n";
// theCat.SetAge(8); const!
return theCat;
1.Making a cat...
2.Simple Cat Constructor...
3.Frisky is 1 years old
4.Frisky is 5 years old
6.Function Two. Returning...
7.Frisky is now 5 years old
8.Frisky is 5 years old
9.Simple Cat Destructor...
Обычно не видят разницы между постоянной ссылкой на объект и
ссылкой на постоянный объект. Сами ссылки нельзя переназначать
и заставить их ссылаться на другой объект, поэтому они всегда
постоянны. Если к ссылке применено ключевое слово const ,
то оно делает постоянным не ссылку , я связанный с ней объект.
Когда использовать ссылки а когда указатели.
Пример
int *pInt=new int;
if(pInt!=NULL)
int &rInt=*pInt;
Совместное использование ссылок и указателей
Не возвращайте ссылку на объект который находится
вне области действия !
#include <iostream>
SimpleCat (int age, int weight);
~SimpleCat() {
int GetAge() {
int GetWeight() {
int itsAge;
int itsWeight;
itsAge = age;
itsWeight = weight;
SimpleCat &rCat = TheFunction();
int age = rCat.GetAge();
std::cout << "rCat is " << age << " years old!\n";
return 0;
SimpleCat Frisky(5,9);
return Frisky;
На компиляторе фирмы Borland программа не компилируется, но для нее подходят
компиляторы Microsoft.
Однако профессиональный программист никогда не станет полагаться на
уступки компилятора
Анализ:
29 SimpleCat &rCat = TheFunction();
SimpleCat &TheFunction()
{
return Frisky;
Содержание