Чтение онлайн

ЖАНРЫ

Освой самостоятельно С++ за 21 день.

Либерти Джесс

Шрифт:

Сокрытие метода базового класса

 В предыдущем примере при обращении к методу Speak из объекта класса Dog программа выполнялась не так, как было указано при объявлении метода Speak в базовом классе. Казалось бы, это то, что нам нужно. Если в классе Mammal есть некоторый метод Move, который замещается в классе Dog, то можно сказать, что метод Move класса Dog скрывает метод с тем же именем в базовом классе. Однако в некоторых случаях результат может оказаться неожиданным.

Усложним ситуацию.

Предположим, что в классе Mammal метод Move трижды перегружен. В одном варианте метод не требует параметров, в другом используется один целочисленный параметр (дистанция), а в третьем — два целочисленных параметра (скорость и дистанция). В классе Dog замещен метод Move без параметров. Тем не менее попытка обратиться из объекта класса Dog к двум другим вариантам перегруженного метода класса Mammal окажется неудачной. Суть проблемы раскрывается в листинге 11.6.

Листинг 11.6. Сокрытие методов

1: //Листинг 11.6. Сокрытие методов

2:

3: #include <iostream.h>

4:

5: class Mammal

6: {

7: public:

8: void Move const { cout << "Mammal move one step\n"; }

9: void Move(int distance) const

10: {

11: cout << "Mammal move ";

12: cout << distance <<" steps.\n";

13: }

14: protected:

15: int itsAge;

16: int itsWeight;

17: };

18:

19: class Dog : public Mammal

20: {

21: public:

22: // Возможно, последует сообщение, что функция скрыта!

23: void Move const { cout << "Dog move 5 steps.\n"; }

24: };

25:

26: int main

27: {

28: Mammal bigAnimal;

29: Dog fido;

30: bigAnimal.Move;

31: bigAnimal.Move(2);

32: fido.Move;

33: // fido.Move(10);

34: return 0;

35: }

Результат:

Mammal move one step

Mammal move 2 steps.

Dog move 5 steps.

Анализ: В данном примере из программы были удалены все другие методы и данные, рассмотренные нами ранее. В строках 8 и 9 в объявлении класса Mammal перегружаются методы Move. В строке 23 происходит замещение метода Move без параметров в классе Dog. Данный метод вызывается для объектов разных классов в строках 30 и 32, и информация, выводимая на экран, подтверждает, что замещение метода прошло правильно.

Однако строка 33 заблокирована, так как она вызовет ошибку компиляции. Хотя логично было предположить, что в классе Dog свободно можно использовать метод Move(int), поскольку замещен был только метод Move, но в действительности в данной ситуации, чтобы использовать Move(int), его также нужно заместить в классе Dog. В случае замещения одного из перегруженных методов скрытыми оказываются все варианты этого метода в базовом классе. Если вы хотите использовать в

производном классе другие варианты перегруженного метода, то их также нужно заместить в этом классе.

Часто случается ошибка, когда после попытки заместить метод в производном классе данный метод оказывается недоступным для класса из-за того, что программист забыл установить ключевое слово const, используемое при объявлении метода в базовом классе. Вспомните, что слово const является частью сигнатуры, а несоответствие сигнатур ведет к скрытию базового метода, а не к его замещению.

Замещение и сокрытие

В следующем разделе главы будут рассматриваться виртуальные методы. Замещение виртуальных методов ведет к полиморфизму, а сокрытие методов разрушает поли- морфизм. Скоро вы узнаете об этом больше.

Вызов базового метода

Даже если вы заместили базовый метод, то все равно можете обратиться к нему, указав базовый класс, где хранится исходное объявление метода. Для этого в обращении к методу нужно явно указать имя базового класса, за которым следуют два символа двоеточия и имя метода. Например: Mammal: :Move.

Если в листинге 11.6 переписать строку 32 так, как показано ниже, то ошибка во время компиляции больше возникать не будет:

32: fido.Mammal::Move;

Такая запись, реализованная в листинге 11.7, называется явным обрашением к методу базового класса.

Листинг 11.7. Явное обращение к методу базового класса

1: //Листинг 11.7. Явное обращение к методу базового класса

2:

3: #include <iostream.h>

4:

5: class Mammal

6: {

7: public:

8: void Move const { cout << "Mammal move one step\n"; }

9: void Move(int distance) const

10: {

11: cout << "Mammal move " << distance;

12: cout << " steps.\n";

13: }

14:

15: protected:

16: int itsAge;

17: int itsWeight;

18: };

19:

20: class Dog : public Mammal

21: {

22: public:

23: void Moveconst;

24:

25: };

26:

27: void Dog::Move const

28: {

29: cout << "In dog move...\n";

30: Mammal::Move(3);

31: }

32:

33: int main

34: {

35: Mammal bigAnimal;

36: Dog fido;

37: bigAnimal.Move(2);

38: fido.Mammal::Move(6);

39: return 0;

40: }

Результат:

Mammal move 2 steps.

Mammal move 6 steps.

Анализ: В строке 35 создается объект bigAnimal класса Mammal, а в строке 36 — объект fido класса Dog. В строке 37 вызывается метод Move(int) из базового класса для объекта класса Dog.

Поделиться с друзьями: