virtual public CocaCola {
public:
CocaColaUkr(void):Company("CocaColaUkr")
{//...}
};
У наведеному прикладі наявна помилка через повторне успадкування класів. Щоб її уникнути, потрібно використовувати віртуальні базові класи.
Допишемо до попереднього прикладу клас Pepsi:
class Pepsi:public Company{
public:
Pepsi():Company("Pepsi"){ }};
Class Corporation:public CocaCola,
public Pepsi {//...};
Тут також буде помилка. Pepsi та CocaCola виводяться з company (хоч у CocaCola company є віртуальним). Щоб помилки не було, клас Company має бути оголошений віртуальним у Pepsi.
Опишемо тепер клас Corporation:
Class Corporatin:public CocaCola,
public CocaColaUkr{ }
У цьому випадку помилка відсутня.
Виклик конструкторів
1. Віртуальні базові класи (ВБК) iнiцiалiзуються (викликається void -конструктор) перед будь-якими не ВБК у тому порядку, у якому вони зустрічаються в графі успадкування.
2. Якщо ВБК має хоча б один конструктор, то вiн повинен мати void -конструктор. Із похідного класу не можна прямо викликати не void -конструктор ВБК. Наприклад:
Class Domastic_animal
{protected:
int size;
public:
Domastic_animal(void)
{cout<<"\n void constructor for Domastic_animal\n";
size=0;}
Domastic_animal(int asize)
{
cout<<"\n multiple constructor for Domastic_animal\n";
size=asize;}
Virtual void print(void)
{cout<<"The size="<<size<<'\n';}
};
Class Cat:public virtual Domastic_animal
{public:
Cat(void)
{cout<<"\n void constructor for Cat\n";}
Cat(int aSize)
{cout<<"\n multiple constructor for Cat\n";
size=aSize;}
Void print(void)
{cout<<"The Cat size\n";
Domastic_animal::print();
}
};
Class Tomcat:public virtual Domastic_animal
{//аналогiчно Cat
public:
Tomcat(void)
{cout<<"\n void constructor for Tomcat\n";}
Tomcat(int aSize)
{cout<<"\n multiple constructor for Tomcat\n";
size=aSize;}
Void print(void)
{cout<<"The Tomcat size\n";
Domastic_animal::print();
}
};
Class Kitten:public Cat,public Tomcat
{public:
Kitten(int aSize)
{cout<<"\n multiple constructor for Kitten\n";
size=aSize;}
Void print(void)
{//аналог функції в класі Cat};
cout<<"The Kitten size\n";
Domastic_animal::print();
}
};
Main()
{Cat aCat(60);
Kitten aKitten(25);
Domastic_animal& myCat=aCat;
Domastic_animal & myKitten=aKitten;
myCat.print();
myKitten.print();}
Надрукується:
Void constructor for Domastic_animal
Multiple constructor for Cat
Void constructor for Domastic_animal
Void constructor for Сat
Void constructor for Tomcat
Multiple constructor for Kitten.
The Cat size
The size=60
The Kitten size
The size=25
Друзі
Інкапсуляція даних – одна з основних переваг ООП. Проте в С++ існує можливість обійти правила інкапсуляції, тобто доступу до різних частин опису класу.
Дружні класи
У класі можна оголосити інший клас дружнім. Один клас (у якому оголошується друг) дає можливість іншому (другу) мати доступ до всіх своїх закритих і захищених членів. Як відомо, відкриті члени завжди доступні. Тому немає необхідності оголошувати один клас другом іншого, щоб дати йому доступ до відкритих членів останнього. Механізм дружніх класів використовується у випадках, коли для двох класів, не пов'язаних "родинними" відношеннями, необхідний доступ до закритих і захищених секцій класів. Нехай оголошено клас
class Aclass{
private:
double value;
public:
Aclass() {v=3.14159;}};
та клас
class Bclass{
private:
Aclass anobject;
public:
Void ShowValue(void)
{cout<<anobject.value;}};
Поле value об'єкта anobject типу Aclass закрите в класі Bclass. Тому в наведеному прикладі у функції ShowValue виникне помилка. Уникнути її можна, якщо оголосити клас Bclass другом класу Aclass, використавши ключове слово friend:
class Aclass{
friend class Bclass;
private:
double value;
public:
Aclass(){value=3.14159;}};
Оголошення дружнього класу може міститись будь-де у протоколі опису класу (не обов'язково на початку формального опису після "{")). При оголошенні дружніх класів потрібно дотримуватись певних правил:
1. У класі мають бути перелічені всі його друзі.
2. Клас, у якому є закриті й захищені члени та дружній інший клас, надає можливість другу мати доступ до своєї закритої частини (за протоколом). Клас не може оголосити сам себе другом іншого класу.
3. Порядок оголошення класів і дружніх до них не має значення. Проте зазвичай дружні класи оголошуються після базових, щоб функції дружніх класів, які вбудовуються, могли звертатись до закритих і захищених частин вихідного класу.
4. Похідні від дружніх класів не є дружніми.
5. Синтаксично похідний клас може бути другом іншого. Результат – аналогічний.
Розглянемо приклад:
class One{
friend class Two;
private:
int x;
protected:
void doublex(void){x*=x;}
public:
One(){x=100;}
One(int n){x=n;}
};
class Two{
private:
One oneobject;
public:
void ShowValues(void);};