1,多继承带来的一个根本性的复杂性:模棱两可.
例如:
#include <iostream>
using namespace std;
class Lottery
{
public:
virtual void draw() { cout << "Lottery" << endl; }
};
class GraphicalObject
{
public:
virtual void draw() { cout << "GraphicalObject" << endl; }
};
class LotterySimulation: public Lottery, public GraphicalObject //多重继承
{
// doesn't declare draw
};
int main()
{
LotterySimulation *pls = new LotterySimulation;
//pls->draw(); // 模棱两可
pls->Lottery::draw(); // fine
pls->GraphicalObject::draw(); // fine
return 0;
}
注:纵使其中一个继承的draw函数时private属性,依旧模棱两可.
原因:"存取限制"不能解除"因多继承而得之members"的模棱两可状态.
理由:改变某个class成员的可存取性,绝不应该连带改变程序的意义.
2,即使这么改了,依旧存在问题:
#include <iostream>
using namespace std;
class Lottery
{
public:
virtual void draw() { cout << "Lottery" << endl; }
};
class GraphicalObject
{
public:
virtual void draw() { cout << "GraphicalObject" << endl; }
};
class LotterySimulation: public Lottery, public GraphicalObject //多重继承
{
// doesn't declare draw
};
class SpecialLotterySimulation: public LotterySimulation
{
public:
virtual void draw() { cout << "SpecialLotterySimulation" << endl; }
};
int main()
{
LotterySimulation *pls = new SpecialLotterySimulation;
//pls->draw(); // 依旧模棱两可
pls->Lottery::draw(); // fine
pls->GraphicalObject::draw(); // fine
return 0;
}
3,一个绕弯的解决方法:
#include <iostream>
using namespace std;
class Lottery
{
public:
virtual void draw() { cout << "Lottery" << endl; }
};
class GraphicalObject
{
public:
virtual void draw() { cout << "GraphicalObject" << endl; }
};
class AuxLottery: public Lottery
{
public:
virtual void lotteryDraw() = 0;
virtual void draw() { lotteryDraw(); }
};
class AuxGraphicalObject: public GraphicalObject
{
public:
virtual void graphicalObjectDraw() = 0;
virtual void draw() { graphicalObjectDraw(); }
};
//注:这两个函数的作用就是为继承而来的draw函数声明一个新名称.
class LotterySimulation: public AuxLottery, public AuxGraphicalObject
{
public:
virtual void lotteryDraw() { cout << "Lottery Part." << endl; }
virtual void graphicalObjectDraw() { cout << "GraphicalObject Part." << endl; }
};
int main()
{
LotterySimulation *pls = new LotterySimulation;
Lottery *pl = pls;
GraphicalObject *pgo = pls;
pl->draw(); // this calls LotterySimulation::lotteryDraw
pgo->draw();// this calls LotterySimulation::graphicalObjectDraw
return 0;
}
4,看下面这个"钻石"
如果你不希望D对象内含多份A成员,那么上述的B和C都将A声明为一个virtual base class.
当A是一个nonvirtual base时,D对象的典型内存布局:
当A是一个virtual base时,D对象的典型内存布局,其中内含两个指针:
5,当virtual base class需要引用计数时:
引用计数被指定于这一base派生类最深的classes的成员初值表.
最简单的办法:避免virtual base classes拥有data成员.
看下面的例子:
A定义了虚拟函数mf(),C重新定义了mf,B和D没有重新定义mf.
D调用哪个mf?直接继承自C的那个,还是间接调用A的那个.
答案:
如果A是B或C的nonvirtual基类,上述调用模棱两可.
如果是virtual基类:调用C::mf.
6,实用:如果你可以避免实用virtual base(避免"钻石"继承),事情会好处理得多.
看一个实例:
class PersonInfo //利用它的实现,private inheritance
{
public:
PersonInfo(DatabaseID pid);
virtual ~PersonInfo();
virtual const char * theName() const;
virtual const char * theBirthDate() const;
virtual const char * theAddress() const;
virtual const char * theNationality() const;
virtual const char * valueDelimOpen() const; // see
virtual const char * valueDelimClose() const; // below
};
const char * PersonInfo::valueDelimOpen() const
{
return "["; // default opening delimiter
}
const char * PersonInfo::valueDelimClose() const
{
return "]"; // default closing delimiter
}
class Person //利用它的接口:public inheritance
{
public:
virtual ~Person();
virtual string name() const = 0;
virtual string birthDate() const = 0;
virtual string address() const = 0;
virtual string nationality() const = 0;
};
class MyPerson: public Person, private PersonInfo // multiple inheritance
{
public:
MyPerson(DatabaseID pid): PersonInfo(pid) {}
//虚函数,重新定义
const char * valueDelimOpen() const { return ""; }
const char * valueDelimClose() const { return ""; }
// 重用PersonInfo的实现
string name() const
{ return PersonInfo::theName(); }
string birthDate() const
{ return PersonInfo::theBirthDate(); }
string address() const
{ return PersonInfo::theAddress(); }
string nationality() const
{ return PersonInfo::theNationality(); }
};