Обратите внимание, что объект, создаваемый в функции main, не является константным и объект Frisky может вызвать метод SetAge. Адрес этого обычного объекта передается функции FunctionTwo, но, поскольку в объявлении функции FunctionTwo заявлено, что передаваемый указатель должен быть константным указателем на константный объект, с этим объектом функция обращается так, как если бы он был константным!
Ссылки в качестве альтернативы
При выполнении программы, показанной в листинге 9.11, устранена необходимость создания временных копий, что сокращает число обращений к конструктору и деструктору класса, в результате чего программа работает более эффективно. В данном примере использовался константный указатель на константный объект, что предотвращало возможность изменения объекта функцией. Однако по-прежнему имеет место некоторая громоздкость синтаксиса, свойственная передаче в функции указателей.
Поскольку, как вам известно, объект никогда не бывает нулевым, внутреннее содержание функции упростилось бы, если бы ей вместо указателя передавалась ссылка. Подтверждение этим словам вы найдете в листинге 9.12.
Листинг 3.12. Передача ссылок на объекты
1: // Листинг 9.12.
2: // Передача ссылок на объекты
3:
4: #include
5:
6: class SimpleCat
7: {
8: public:
9: SimpleCat;
10: SimpleCat(SimpleCat&);
11: ~SimpleCat;
12:
13: int GetAge const { return itsAge; }
14: void SetAge(int age) { itsAge = age: }
15:
16: private:
17: int itsAge;
18: };
19:
20: SimpleCat::SimpleCat
21: {
22: cout << "Simple Cat Constructor...\n";
23: itsAge = 1;
24: }
25:
26: SimpleCat::SimpleCat(SimploCat&)
27: {
28: cout << "Simple Cat Copy Cunstructor...\n";
29: }
30:
31: SimpleCat::~SimpleCat
32: {
33: cout << "Simple Cat Destructor...\n";
34: }
35:
36: const SimpleCat & FunctionTwo (const SimpleCat & theCat);
37:
38: int main
39: {
40: cout << "Making a cat...\n";
41: SimpleCat Frisky;
42: cout << "Frisky is " << Frisky.GetAge << " years old\n";
43: int age = 5;
44: Frisky,SetAge(age);
45: cout << "Frisky is " << Frisky.GetAge << " years old\n";
46: cout << "Calling FunctionTwo...\n";
47: FunctionTwo(Frisky);
48: cout << "Frisky is " << Frisky.GetAge << " years old\n";
49: return 0;
50: }
51:
52: // functionTwo, passes a ref to a const object
53: const SimpleCat & FunctionTwo (const SimpleCat & theCat)
54: {
55: cout << "Function Two. Returning...\n";
56: cout << "Frisky is now " << theCat.GetAge;
57: cout << " years old \n";
58: // theCat.SetAge(8); const!
59: return theCat;
60: }
Результат:
Making a cat...
Simple Cat constructor...
Frisky is 1 years old
Frisky is 5 years old
Calling FunctionTwo...
FunctionTwo. Returning...
Frisky is now 5 years old
Frisky is 5 years old
Simple Cat Destructor...
Анализ:
Результат работы этой программы идентичен результату, показанному после листинга9.11. Единственное существенное изменение — функция FunctionTwo теперь принимает и возвращает ссылки на константный объект. И вновь-таки работа со ссылками несколько проще, чем работа с указателями, хотя при этом достигается та же экономия средств и эффективность выполнения, а также обеспечивается надежность за счет использования спецификатора const.Константные ссылки
Когда лучше использовать ссылки, а когда - указатели
Опытные программисты безоговорочно отдают предпочтение ссылкам, а не указателям. Ссылки проще использовать, и они лучше справляются с задачей сокрытия информации, как вы видели в предыдущем примере.
Но ссылки нельзя переназначать. Если же вам нужно сначала указывать на один объект, а затем на другой, придется использовать указатель. Ссылки не могут быть нулевыми, поэтому, если существует хоть какая-нибудь вероятность того, что рассматриваемый объект может быть нулевым, вам нельзя использовать ссылку. В этом случае необходимо использовать указатель.
В качестве примера рассмотрим оператор new. Если оператор new не сможет выделить память для нового объекта, он возвратит нулевой указатель. А поскольку ссылка не может быть нулевой, вы не должны инициализировать ссылку на эту память до тех пор, пока не проверите, что она не нулевая. В следующем примере показано, как это сделать: