Класс может иметь не один базовый класс, а несколько. Таким образом, на новом уровне можно создать некую объединяющую сущность. Допустим, у нас есть два не связанных между собой класса Point и ColorPoint. Мы попробуем объединить их в одном классе и создать класс Rectangle.
class Point
{
protected:
int x,y;
public:
Point ():x(50),y(50) {}
};
class ColorPoint
{
protected:
int x1,y1;
int color;
public:
ColorPoint ():x1(100),y1(100),color(5) {}
};
class RectangleFill : public Point, public ColorPoint
{
protected:
int colorfill;
public:
RectangleFill (): Point(), ColorPoint(), colorfill(10) {}
void Show()
{
cout<<"("<<x<<","<<y<<")-("<<x1<<","<<y1<<") "<<color<<" "<<colorfill<<endl;
}
};
void main()
{
RectangleFill rf;
rf.Show(); //(50,50)-(100,100) 5 10
}
В случае множественного наследования, базовые классы объявляются при объявлении, а конструкторы базовых классов вызываются в списке инициализации, через запятую.
Теперь рассмотрим пример множественного наследования, в случае, когда нам нужно перегрузить конструкторы и методы класса-потомка.
class Point
{
protected:
int x,y;
public:
Point ():x(50),y(50) {}
Point (int nx,int ny):x(nx),y(ny) {}
void Show()
{
cout<<"("<<x<<","<<y<<")";
}
};
class ColorPoint
{
protected:
int x1,y1;
int color;
public:
ColorPoint ():x1(100),y1(100),color(5) {}
ColorPoint (int nx1,int ny1,int ncolor):x1(nx1),y1(ny1),color(ncolor) {}
void Show()
{
cout<<"("<<x1<<","<<y1<<") "<<color;
}
};
class RectangleFill : public Point, public ColorPoint
{
protected:
int colorfill;
public:
RectangleFill (): Point(), ColorPoint(), colorfill(10) {}
RectangleFill (int nx,int ny,int nx1,int ny1,int ncolor,int ncolorfill):
Point(nx,ny), ColorPoint(nx1,ny1,ncolor),colorfill(ncolorfill) {}
void Show()
{
Point::Show();
ColorPoint::Show();
cout<<" "<<colorfill<<endl;
}
};
void main()
{
RectangleFill rf;
rf.Show(); //(50,50)-(100,100) 5 10
RectangleFill rf1(20,20,40,40,2,15);
rf1.Show(); //(20,20)-(40,40) 2 15
}
На примере видно, что перегрузка конструктором ничем не отличается, за тем исключением, что мы вызываем конструкторы как одного базового класса, так и другого. При перегрузке же функций мы указываем функцию какого класса мы хотим использовать. В нашем случае, одноименная функция Show показывает отрабатывает трижды, как функция класса Point, функция класса ColorPoint и как функция самого класса Rectangle. Неопределенность, состоящую в том, что на момент запуска функции Show компилятор не знает какую именно функцию запускать, мы разрешаем за счет использования операции разрешения «::».Если нам нужен еще какой-то алгоритм, то мы его прописываем между фигурных скобок.
В случае, если у нас в классе наследником такого типа не описана функция Show, мы получим от компилятора сообщение об ошибке, т. к. в этом случае ему будет не ясно, из какого класса брать реализацию функции Show.
Если в одном из базовых классов мы изменим имя функции, например на Show1(), то в этом случае, наследование будет выполняться в штатном режиме.
Нужно отметить, что в последствии, мировое информационное сообщество отказалось от множественного наследования, т. к. программирование с множественным наследованием, - процесс довольно сложный, сложно учесть все особенности реализации базовых классов.