Главная->Інформатика та програмування->Содержание->Доступ к обычным методам через указатели

ОБЪЕКТНО-ОРИЕНТИРОВАННОЕ ПРОГРАММИРОВАНИЕ В C++ (4-Е ИЗДАНИЕ) (часть 11) онлайн

Доступ к обычным методам через указатели

Наш первый пример покажет, что бывает, когда базовый и производные классы

содержат функции с одним и тем же именем, и к ним обращаются с помощью

указателей, но без использования виртуальных функций.

Листинг 11.1. Программа NOTVIRT

 

// notvirt.cpp

// Доступ к обычным функциям через указатели

#include <iostream>

using namespace std;

///////////////////////////////////////////////

class Base                //Базовый класс

      {

      public:

   void  show()           //Обычная функция

      {  cout << "Base\n"; }

      };

//////////////////////////////////////////////

class Derv1 : public Base //Производный класс 1

      {

      public:

 

Листинг 11.1 (продолжение)

 

void  show()     

      {  cout << "Derv1\n"; }

      };

//////////////////////////////////////////////

class Derv2 : public Base //Производный класс 2

      {

      public:

   void  show()     

      {  cout << "Derv2\n"; }

      };

//////////////////////////////////////////////

int main()

{     

      Derv1 dv1;          //Объект производного класса 1

      Derv2 dv2;          //Объект производного класса 2

      Base* ptr;          //Указатель на базовый класс

 

      ptr = &dv1;         //Адрес dv1 занести в указатель

      ptr->show();         //Выполнить show()

      ptr = &dv2;         //Адрес dv2 занести в указатель

      ptr->show();        //Выполнить show()

      return 0;

 }

 

Итак, классы Dervl и Derv2 являются наследниками класса Base. В каждом из

этих трех классов имеется метод show(). В main() мы создаем объекты классов

Dervl и Derv2, а также указатель на класс Base. Затем адрес объекта порожденно-

го класса мы заносим в указатель базового класса:

ptr = &dv1; //Адрес объекта порожденного класса заносим в //указатель базового

Но постойте, а компилятор на нас не обидится за то, что мы присваиваем ад-

рес объекта одного типа указателю на другой тип? Оказывается, наоборот —

компилятор будет просто счастлив, потому что проверка типов отдыхает в этой

ситуации. Мы скоро поймем, почему. Дело в том, что указатели на объекты порож-

денных классов совместимы по типу с указателями на объекты базового класса.

Теперь хорошо бы понять, какая же, собственно, функция выполняется в этой

строчке:

ptr->show();

Это функция Base::show() или Dervl::show()? Опять же, в последних двух

строчках программы NOTVIRT мы присвоили указателю адрес объекта, при-

надлежащего классу Derv2, и снова выполнили

ptr->show();

Так какая же из функций show() реально вызывается? Результат выполнения

программы дает простой ответ:

Base

Base

Как видите, всегда выполняется метод базового класса. Компилятор не смот-

рит на содержимое указателя ptr, а выбирает тот метод, который удовлетворяет

типу указателя, как показано на рис. 11.1.

 

Да, иногда именно это нам и нужно, но таким образом не решить поставлен-

ную в начале этой темы проблему доступа к объектам разных классов с помо-

щью одного выражения.

Рис. 11.1. Доступ через указатель без использования виртуальных функций

 

4