`
kmplayer
  • 浏览: 497038 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

条款43:明智地使用多继承

阅读更多
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(); }
};
  • 大小: 12.4 KB
  • 大小: 11.4 KB
  • 大小: 12.7 KB
  • 大小: 17.9 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics