問題來了:在類D的實例中將有兩份類A的變量,這種數據冗余的現象我們不能容忍其存在?這就會需要用到虛繼承!!!廢話不多說直接上代碼,直接粘貼可用。
#include <iostream>
#include <stdlib.h>#include <string>
using namespace std;
/**
?* 定義人類: Person
?*/
class Person
{
public:
? ? Person(string color = "blue"):m_strColor(color)
{
cout << "Person" << endl;
}
~Person()
{
cout << "~Person" << endl;
}
void eat()
{
? ? ? ? cout << m_strColor << endl;
? ? ? ? // cout << m_iAge << endl;
cout << "Person -- eat" << endl;
}
protected:
? ? string m_strColor;
};
/**
?* 定義工人類: Worker
?* 虛繼承人類
?*/
class Worker : ?virtual?public Person
{
public:
Worker(string name,string color):Person("Worker"+color)
{
m_strName = name;
cout << "Worker" << endl;
}
~Worker()
{
cout << "~Worker" << endl;
}
void work()
{
cout << m_strName << endl;
cout << "work" << endl;
}
protected:
string m_strName;
};
/**
?* 定義兒童類:Children
?* 虛繼承人類
?*/
class Children :?virtual?public Person
{
public:
Children(int age,string color):Person("Children"+ color)
{
m_iAge = age;
cout << "Children" << endl;
}
~Children()
{
cout << "~Children" << endl;
}
void play()
{
? ? ? ? cout<<
cout << m_iAge << endl;
cout << "play" << endl;
}
protected:
int m_iAge;
};
/**
?* 定義童工類:ChildLabourer
?* 公有繼承工人類和兒童類
?*/
class ChildLabourer:public Children,public Worker
{
public:
ChildLabourer(string name, int age,string color):Worker(name,color),Children(age,color)
{
cout << "ChildLabourer" << endl;
}
~ChildLabourer()
{
cout << "~ChildLabourer" << endl;
}
};
int main(void)
{
? ? // 用new關鍵字實例化童工類對象
ChildLabourer * p = new ChildLabourer("qq",14,"yellow");
? ? // 調用童工類對象各方法。
// ? p->eat();
? ? ? ? p->Worker::eat();
? ? ? ? p->Children::eat();
p->work();
p->play();
delete p;
p = NULL;
return 0;
}
輸出:
Person Children Worker ChildLabourer blue Person -- eat blue Person -- eat qq work 0x60314814 play ~ChildLabourer ~Worker ~Children ~Person如果不加virtual關鍵字時候的輸出:
Person Children Person Worker ChildLabourer Workeryellow Person -- eat Childrenyellow Person -- eat qq work 0x60310814 play ~ChildLabourer ~Worker ~Person ~Children ~Person分析:
(1)不加virtual情況:
不加virtual,也就是不是虛繼承的情況下,在實例化童工這個類的時候,會按繼承順序,先調用類Children的構造函數再調用類Worker的構造函數,最后調用自己的構造函數,而調用Children和Worker的構造函數的時候又會分別先調用它們的基類Person的構造函數,這樣就會生成兩個Person的對象,從而生成兩份Person所含有的數據成員,即童工類ChildLabourer在實例化的時會生成在內存中會生成兩份Person的數據成員,所以在調用Children和Worker的eat()函數的時候,會分別打印出Workeryellow和Childrenyellow,(這里注意Children和Worker里面的eat()都是從Person繼承來的,因此分別都會打印出Person --eat;還要注意調用方式:p->Worker::eat();p->Children::eat())
銷毀對象時,會先調用自己的析構函數,再調用兩個基類的析構函數,兩個基類的析構函數調用之前都會先調用Person的析構函數。調用析構函數的順序和調用構造函數相反。
(2)加virtual的情況:
加virtual以后,從輸出結果可以看出,在實例化童工類ChildrenLabourer時,構造函數的調用順序比較正常,只調用了一次Person,析構函數的調用也只會調用一次Person的析構函數,這說明實例化童工類時只會生成一份Person的對象,表明了在對象的內存空間中僅僅能夠包含一份虛基類的對象,而且打印的結果都是blue,即ChildrenLabourer的數據不會再傳入虛基類Person。這就講數據冗余的問題解決了。