Слайд 1Тема: Виртуальные базовые классы
Проблема наследования базовым классам, имеющим общего предка
Как
управлять числом копий свойств общего предка
Как избежать повторного обращения к
методу общего предка
Конструирование объекта класса у которого родители имеют общего предка
Слайд 2Постановка проблемы
Бывает, что класс оказывается потомком различных базовых классов, имеющих
общего предка
Окно Bottom_Window при изменении размера отображает последние строки
Окно
Shell_Window было рассмотрено раньше
Как сделать окно Bottom_Shell_Window ?
Слайд 4Класс Bottom_Window
class Bottom_Window : public Window {
public:
Bottom_Window( const
Point& upper_left ,
const Point& size , const String& utitle );
void change_size( const Point& new_size );
};
Слайд 5Метод change_size()
класса Bottom_Window
void Bottom_Window :: change_size ( const Point& new_size
)
{
int shrinkage = size( ).y( ) - new_size.y( ) ;
for( int i = 0 ; i < shrinage ; i++ ) scroll_up( );
Window::change_size ( new_size );
}
Слайд 6Класс Bottom_Shell_Window
class Bottom_Shell_Window : public Sell_Window,
public Bottom_Window
{
public:
Bottom_Shell_Window(
const Point& upleft,
const Point& size, const String& title);
void change_size(const Point& new_size);
};
Слайд 7Объект класса Bottom_Shell_Window
Слайд 8Объект класса Bottom_Shell_Window
Слайд 9Классы Shell_Window и Bottom_Window
class Shell_Window : virtual public Window {
//
…………..
};
class Bottom_Window : virtual public Window {
// …………..
};
Слайд 10Метод change_size()
класса Bottom_Shell_Window
void Bottom_Shell_Window :: change_size(const Point& size )
{
Bottom_Window::change_size (
size ) ;
Shell_Window::change_size ( size );
}
Слайд 13Класс Bottom_Window
class Bottom_Window : virtual public Window {
public:
Bottom_Window( const
Point& upleft,
const Point& size, const String& title);
void change_size(const Point&
new_size);
protected:
void befor_change_size(const Point& new_size);
void after_change_size(const Point& new_size);
};
Слайд 14Методы класса Bottom_Window
void Bottom_Window::befor_change_size(const Point& nsz) {
int shrinkage
= size( ).y( ) - nsz.y( ) ;
for( int i = 0 ; i < shrinage ; i++ ) scroll_up( );
}
void Bottom_Window::after_change_size(const Point& ) {
// не нужно ничего делать после изменения размера
}
void Bottom_Window::change_size(const Point& new_size) {
befor_change_size( new_size ) ;
Window::change_size( new_size ) ;
after_change_size( new_size );
};
Слайд 15Класс Shell_Window
class Shell_Window : virtual public Window {
public:
Shell_Window( const
Point& upleft,
const Point& size, const String& title);
int execute (
const String& command );
void change_size(const Point& new_size);
protected:
Point valid_new_size(const Point& new_size);
};
Слайд 16Методы класса Bottom_Window
const Point min_SW_size (40,3);
Point Shell_Window::valid_new_size(const Point& new_size)
{
return max( new_size, min_SW_size);
}
void Shell_Window::change_size(const Point& new_size) {
Window::change_size(
valid_new_size(new_size) ) ;
};
Слайд 17Метод change_size()
класса Bottom_Shell_Window
void Bottom_Shell_Window :: change_size(const Point& size )
{
Point new_size
= Shell_Window::valid_new_size ( size );
Bottom_Window::befor_change_size ( new_size ) ;
Window::change_size ( new_size );
Bottom_Window::after_change_size ( new_size ) ;
}
Слайд 18Проблема конструктора
Если у класса не виртуальный предок, то при конструировании
объекта класса однозначно вызывается конструктор предка (статическое связывание)
Класс, производный от
такого базового класса не знает о «дедушке», и его конструктор должен передать параметры только конструктору класса- «папы»
При множественном наследовании, если «родители» класса имеют общего не виртуального предка, то для объекта-«внука» будет дважды вызываться конструктор «деда»
Слайд 19Не виртуальное наследование
class Shell_Window : public Window {
// …………..
};
class Bottom_Window
: public Window {
// …………..
};
class Bottom_Shell_Window : public Shell_Window ,
public Bottom_Window {
// …………..
};
Слайд 20Дублирование вызова конструктора
Конструктор класса Window
Слайд 21Решение проблемы конструктора
Если у класса виртуальный предок, то для его
классов-«детей» конструирование объекта зависит от происхождения остальных «родителей» (динамическое связывание)
При
множественном наследовании, если «родители» класса имеют общего виртуального предка, то для объекта-«внука» дважды вызываться конструктор «деда» не будет
Это значит, что класс, производный от таких классов-«родителей» должен знать о «дедушке», и его конструктор должен передать параметры не только конструкторам классов-«родителей», но и конструктору класса-«деда»
Слайд 22Виртуальное наследование
class Shell_Window : virtual public Window {
// …………..
};
class Bottom_Window
: virtual public Window {
// …………..
};
class Bottom_Shell_Window : public Shell_Window
,
public Bottom_Window {
// …………..
};
Слайд 23Конструктор класса Shell_Window
Управление конструкторами предков
Конструктор класса Window
Конструктор класса Bottom_Window
Слайд 24Конструкторы классов
Bottom_Window и Shell_Window
Bottom_Window:: Bottom_Window (const Point& up_left, const
Point& size, const String& title) : Window (up_left, size, title)
{
}
Shell_Window:: Shell_Window (const Point& up_left, const Point& size, const String& title) : Window (up_left, valid_new_size(size), “|”+title+“|”)
{ }
Слайд 25Конструктор класса
Bottom_Shell_Window
Bottom_Shell_Window:: Bottom_Shell_Window (
const Point& up_left,
const Point& size,const String& title) :
Window(up_left, Sell_Window::valid_new_size(size),“|”+title+“|”),
Shell_Window(up_left, Sell_Window::valid_new_size(size), “|”+title+“|”) ,
Bottom_Window(up_left, Sell_Window::valid_new_size(size), “|”+title+“|”) ,
{ }
Слайд 26Создание объекта класса
Bottom_Shell_Window
Выделяется память
Конструктор класса Bottom_Shell_Window вычисляет аргументы
для конструктора класса Window
Выполняется тело конструктора класса Window
Конструктор класса Bottom_Shell_Window
вычисляет аргументы для конструкторов класса Bottom_Window и Shell_Window
Конструкторы классов Bottom_Window и Shell_Window НЕ вычисляет аргументы для конструктора класса Window
Выполняются тела конструкторов классов Bottom_Window и Shell_Window
Выполняется тело конструктора класса Bottom_Shell_Window
Слайд 27РЕЗЮМЕ
У базовых классов некоторого производного класса может быть общий предок,
что надо учитывать
Виртуальное наследование общему предку для базовых классов позволяет
избежать дублирование свойств общего предка в производном классе
Использование вспомогательных методов в базовых классах позволяет избежать повторного вызова методов общего предка в методах производного класса
Компилятор позволяет избежать дублирование вызова конструктора общего предка при создании объекта производного класса
Конструктор производного класса должен задавать параметры конструкторов базовых классов и конструктора общего виртуального предка