Освой самостоятельно С++ за 21 день.
Шрифт:
Передачу объектов как значений можно сравнить с передачей музею фотографии шедевра вместо самого шедевра. Если какой-нибудь хулиган испортит фотографию, то никакого вреда при этом оригиналу нанесено не будет. А передачу объекта как ссылки можно сравнить с передачей музею своего домашнего адреса и приглашением гостей посетить ваш дом и взглянуть в вашем присутствии на драгоценный шедевр.
Решить проблему можно, передав в функцию указатель на константный объект класса SimpleCat. В этом случае к данному объекту могут применяться только константные
Листинг 9.11. Передача константных указателей
1: // Листинг 9.11.
2: // Передача константных указателей на объекты
3:
4: #include <iostream.h>
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(SimpleCat&)
27: {
28: cout << "Simple Cat Copy Constructor...\n";
29: }
30:
31: SimpleCat::~SimpleCat
32: {
33: cout << "Simple Cat Destructor...\n";
34: }
35:
36: const SimpleCat * const FunctionTwo (const SimpleCat * const theCat);
37:
38: int main
39: {
40: cout << "Making а cat...\n";
41: SimpleCat Frisky;
42: cout << "Frisky is " ;
43: cout << Frisky.GetAge;
44: cout << " years old\n";
45: int age = 5:
46: Frisky.SetAge(age);
47: cout << "Frisky is " ;
48: cout << Frisky.GetAge;
49: cout << " years old \n";
50: cout << "Calling FunctionTwo...\n";
51: FunctionTwo(&Frisky);
52: cout << "Frisky is ";
53: cout << Frisky.GetAge;
54: cout << " years_ald\n";
55: rsturn 0;
56: }
57:
58: // functionTwo, passes a const pointer
59: const SimpleCat * const FunctionTwo (const SimpleCat * const theCat)
60: {
61: cout << "Function Two, Returning...\n";
62: cout << "Frisky is now " << theCat->GetAge;
63: cout << " years old \n";
64: // theCat->SotAge(8): const!
65: return theCat;
66: }
Результат:
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...
Анализ: В класс SimpleCat были добавлены две функции доступа к данным: метод GetAge (строка 13), который является константной функцией, и метод SetAge (строка 14), который не является константным. В этот класс была также добавлена переменная-член itsAge (строка 17).
Конструктор, конструктор-копировщик и деструктор по-прежнему определены для вывода на экран своих сообщений. Однако конструктор-копировщик ни разу не вызывался, поскольку объект был передан как ссылка и поэтому никаких копий объекта не создавалось. В строке 41 был создан объект со значением возраста, заданным по умолчанию. Это значение выводится на экран в строке 42.
В строке 46 переменная itsAge устанавливается с помощью метода доступа SetAge, а результат этой установки выводится на экран в строке 47. В этой программе функция FunctionOne не используется, но вызывается функция FunctionTwo, которая слегка изменена. Ее объявление занимает строку 36. На этот раз и параметр, и значение возврата объявляются как константные указатели на константные объекты.
Поскольку и параметр, и возвращаемое значение передаются как ссылки, никаких копий не создается и конструктор-копировщик не вызывается. Однако указатель в функции FunctionTwo теперь является константным, следовательно, к нему не может применяться неконстантный метод SetAge. Если обращение к методу SetAge в строке 64 не было бы закомментировано, программа не прошла бы этап компиляции.
Обратите внимание, что объект, создаваемый в функции main, не является константным и объект Frisky может вызвать метод SetAge. Адрес этого обычного объекта передается функции FunctionTwo, но, поскольку в объявлении функции FunctionTwo заявлено, что передаваемый указатель должен быть константным указателем на константный объект, с этим объектом функция обращается так, как если бы он был константным!
Ссылки в качестве альтернативы
При выполнении программы, показанной в листинге 9.11, устранена необходимость создания временных копий, что сокращает число обращений к конструктору и деструктору класса, в результате чего программа работает более эффективно. В данном примере использовался константный указатель на константный объект, что предотвращало возможность изменения объекта функцией. Однако по-прежнему имеет место некоторая громоздкость синтаксиса, свойственная передаче в функции указателей.
Поскольку, как вам известно, объект никогда не бывает нулевым, внутреннее содержание функции упростилось бы, если бы ей вместо указателя передавалась ссылка. Подтверждение этим словам вы найдете в листинге 9.12.
Листинг 3.12. Передача ссылок на объекты
1: // Листинг 9.12.
2: // Передача ссылок на объекты
3:
4: #include <iostream.h>
5:
6: class SimpleCat
7: {
8: public:
9: SimpleCat;
10: SimpleCat(SimpleCat&);