Шаг 27.
Множественное наследование. Дублирование классов

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

    При множественном наследовании никакой класс не может больше одного раза использоваться в качестве непосредственного базового. Однако класс может больше одного раза быть непрямым базовым классом:

class X { ...; f(); ... }; 
class Y: public X { ... }; 
class Z: public X { ... }; 
class D: public Y, public Z { ... };

    В данном примере класс X дважды опосредованно наследуется классом D. Особенно хорошо это видно в направленном ациклическом графе (НАГ):


Рис.1. Двойное наследование класса X

    Проиллюстрированное дублирование класса соответствует включению в производный объект нескольких объектов базового класса. В нашем примере существуют два объекта класса X, и поэтому для устранения возможных неоднозначностей вне объектов класса D нужно обращаться к конкретному компоненту класса X, используя полную квалификацию: D::Y::X::f() или D::Z::Х::f(). Внутри объекта класса D обращения упрощаются: Y::Х::f() или Z::Х::f(), но тоже содержат квалификацию.

    В качестве содержательного примера с дублированием непрямого базового класса изменим класс square) так, чтобы он был наследникм класса point). Новый класс назовем square1:

// SQUARE1.CPP - класс "квадрат", наследник класса POINT.
#ifndef SQUARE1
#define SQUARE1 1
#include <conio.h>   //Для функции gotoxy();
#include "point.cpp" //Определение класса POINT.
class square1 : public point
{
	int  lq;    //Длина стороны квадрата.
	//Вспомогательная функция рисования:
	void rissquare(void);
  public:
	 // Конструктор класса SQUARE1:
	 square1 (int xi, int yi, int li):
                point(xi,yi)
			 { lq = li;}
	 ~square1()     // Деструктор класса SQUARE1.
	  { hide();    // Убрать с экрана изображение квадрата.
		}
  void hide();    // Убрать с экрана изображение квадрата.

void show() //Изобразить квадрат на экране дисплея.
{ rissquare();
}

}; //Конец определения класса.

void square1::rissquare(void)
{
  int d=lq/2;
  for (int i=-d; i<=d; i++)
	{
	  gotoxy(x+i,y+d); cout << "=";
	  gotoxy(x+i,y-d); cout << "=";
	}
	for (int j=-d; j<=d; j++)
	{
	  gotoxy(x-d,y+j); cout << "=";
	  gotoxy(x+d,y+j); cout << "=";
	}
}

void square1::hide()      // Убрать с экрана изображение квадрата.
{
  // Стереть изображение с экрана:
  int d=lq/2;
  for (int i=-d; i<=d; i++)
	{
	  gotoxy(x+i,y+d); cout << " ";
	  gotoxy(x+i,y-d); cout << " ";
	}
	for (int j=-d; j<=d; j++)
	{
	  gotoxy(x-d,y+j); cout << " ";
	  gotoxy(x+d,y+j); cout << " ";
	}
}
#endif
Текст этого класса можно взять здесь.

    Текст программы, использующей классы square1 и (star), остался без изменений:

#include<iostream.h>
#include "square1.cpp"
#include "star.cpp"
class starsqrt: public star, public square1
{
  public:
	  starsqrt (int xi, int yi, int ri):
			star(xi,yi,ri),
			square1 (xi,yi,2*ri) {}
	  void show()
	  { star::show();
		 square1::show(); }
	  void hide ()
	  { star::hide();
		 square1::hide(); }
};

void main()
{
  starsqrt A(5,7,4);
  starsqrt B(18,12,6);
  A.show();  getch();
  B.show();  getch();
  A.hide();  getch();
  B.hide();  getch();
}
Текст этой программы и остальные классы можно взять здесь.

    Как избежать двойного наследования базовых классов? Ответ на этот вопрос будет дан на следующем шаге.

    На следующем шаге мы рассмотрим виртуальные базовые классы.




Предыдущий шаг Содержание Следующий шаг