
Void main ( )
{
Coord C ; // помилка: не можна створити об'єкт абстрактного класу
Dot D ; // помилка: не можна створити об'єкт абстрактного класу
}
Шляхом завдання чисто віртуальної функції Print ( ) при проектуванні класу Coord розроблювач класу домагається того, що будь-який неабстрактний клас, що є похідним класу Coord, не може бути реалізований без функції Print ( ).
До абстрактних класів застосовні наступні правила:
не можна оголосити представник абстрактного класу;
абстрактний клас не може використовуватися в якості типу аргументу, переданого функції;
абстрактний клас не може використовуватися в якості типу повертаємого значення функції;
не можна здійснювати явне перетворення типу об'єкта до типу абстрактного класу;
можна оголосити вказівник або посилання на абстрактний клас.
Віртуальні базові класи
У складній ієрархії класів при множиннім спадкуванні може вийти так, що похідний клас побічно успадкує два або більш екземпляра того самого класу..
class Ground
{
int x ;
public :
Int Getx ( ) { return X ; }
void Setx ( int X ) { x = X ; }
}
class Basel : public Ground
{
}
class Base2 : public Ground
{
}
class Derived : public Base1, public Base2
{
}
Void main ( )
{
Derived ob ; // створення об'єкта похідного класу
ob.Setx ( 1 ) ;
int z = ob.Getx ( ) ;
}
Тут клас Derived побічно успадковує клас Ground через свої базові класи Base1 і Base2. Тому при компіляції наведеного прикладу виникнуть помилки, викликані неоднозначністю звертання до членів класу Getx ( ) у рядках:
ob.Setx ( 0 ) ;
int z = ob.Getx ( ) ;
Щоб уникнути цієї неоднозначності, можна використовувати кваліфікацію імен, застосувавши операцію дозволу видимості:
ob.Base1 :: Setx ( 1 ) ;
int z = ob.Base1 :: Getx ( ) ;
Можна також кваліфікувати ці виклики в такий спосіб:
ob.Base2 :: Setx ( 1 ) ;
int z = ob.Base2 :: Getx ( ) ;
Хоча цей спосіб і дозволяє уникнути неоднозначності при виклику, проте, клас Ground буде включений до складу класу Derived двічі, збільшуючи його розмір. Уникнути повторного включення непрямого базового класу в похідний клас можна, давши вказівку компіляторові використовувати віртуальний базовий клас. Це здійснюється за допомогою ключового слова virtual, яке вказується перед специфікатором наслідуваного доступу або після нього. Наступний приклад є модифікованим варіантом попередн, використовують клас Ground у якості віртуального базового класу.
class Ground
{
int x ;
public :
Int Getx ( ) { return X ; }
void Setx ( int X ) { x = X ; }
}
class Basel : virtual public Ground
{
}
class Base2 : virtual public Ground
{
}
class Derived : public Base1, public Base2
{
}
Void main ( )
{
Derived ob ; // створення об'єкта похідного класу
ob.Setx ( 1 ) ;
int z = ob.Getx ( ) ;
}
У цьому випадку клас Derived містить один екземпляр класу Ground, і виклики
ob.Setx ( 1 ) ;
int z = ob.Getx ( ) ;
не приводять до появи повідомлень компілятора про помилки, пов'язані з неоднозначністю. Звідси випливає загальна рекомендація: якщо розробляється ієрархія класів і даний клас успадковується декількома класами, треба перед специфікаторами наслідуваного доступу вказати ключове слово virtual.
У випадку, якщо клас має один або кілька базових класів, їх конструктори викликаються перед викликом конструктора похідного класу. Конструктори базових класів викликаються в тому порядку, у якім вони оголошені в списку спадкування. Оголошення базового класу віртуальним змінює порядок виклику конструкторів при створенні екземпляра похідного класу. Конструктори віртуальних базових класів викликаються першими, раніше конструкторів невіртуальних базових класів. Якщо віртуальних базових класів декілька, їхні конструктори викликаються в порядку їх оголошення в списку спадкування. Потім викликаються конструктори невіртуальних базових класів у порядку їх оголошення в списку спадкування й, нарешті, викликається конструктор похідного класу. Якщо якийсь віртуальний клас є похідним невіртуального базового класу, цей невіртуальний базовий клас конструюється першим (інакше не можна буде викликати конструктор віртуального базового класу).
Якщо ієрархія класів містить кілька екземплярів віртуального базового класу, цей базовий клас конструюється тільки один раз. Якщо все-таки існують як віртуальний, так і невіртуальний екземпляри цього базового класу, конструктор базового класу викликається один раз для всіх віртуальних екземплярів цього базового класу, а потім ще раз для кожного невіртуального екземпляра цього базового класу.
Деструктори викликаються в порядку, зворотному конструкторам.