Effective C++(条款39-40)

条款39:明智而审慎的使用private继承

private继承意味着is-implemented-in-terms-of(根据某物实现出)。它通常比复合的级别低。但是当继承类需要访问基类的protected成员,或需要重新定义继承而来的virtual函数时,这么设计是合理的。


先了解一下private继承的特点:

1、如果类之间的继承关系是private,编译器不会将一个继承类对象转换为一个基类对象,这意味着private继承并不是is-a的关系。

class Person  
{  
protected:  
    string name;  
};  
  
class Student:private Person  
{  
private:  
    string schoolNumber;  
};  
  
void eat(const Person& p)  
{  
    cout<<"eat"<<endl;  
}  
  
void study(const Student& s)  
{  
    cout<<"study"<<endl;  
}  
  
int main()  
{  
    Person p1;  
    eat(p1);  
    Student s1;  
    study(s1);  
//  eat(s1);错误  
    return 0;  
}  


2、由private base class继承而来的所有成员,在继承类中都会变成private属性。纵使他们在基类中原本是protected或public属性。


因此,private继承意味着:根据某物实现。这与前面条款介绍的复合很类似。private继承意味只有实现部分被继承,接口部分应该被略去。继承类根据基类实现而得,不存在其他的什么关系了。在大多数时候,我们应该使用复合,而不是private继承来实现这种功能。但是当有protected成员和虚函数牵扯进来的时候,我们又不得不用private继承。


其次,与复合相比,private可以使空基类的最优化。先看一个例子:

//定义一个空基类  
class Empty{};  
  
class HoldsAnInt  
{  
private:  
    int x;  
    Empty e;//复合  
};  

在vs中,sizeof(int)为4,sizeof(Empty)为1,sizeof(HoldsAnInt)为8这似乎有悖于我们学过常理:首先,类的大小取决于其数据成员的大小。sizeof(Empty)应该为0,但是由于在编译器会将它的大小设为1,而“齐位需求”会将它放大为1个int,所以,izeof(HoldsAnInt)为8。但是,如果使用的是private继承来实现,就不存在这种问题了:sizeof(HoldsAnInt)只有一个int的大小:4。


 总之,private继承意味着根据某物实现。当派生类需要访问基类的的受保护成员或者重新定义虚函数时,我们才使用它。而且private继承可以是得空基类最优化,如果在开发中需要是得对象尺寸最小,那么也用得着它。“明智而审慎的使用private继承”意味着,在考虑过所有其他方案后,如果仍然认为private继承是“表现程序内两个类之间的关系”的最佳办法,这才使用它




条款40:明智而审慎的使用多重继承

1、多重继承比单一继承复杂。它可能导致新的歧义性,以及对virtual继承的需要

当使用多重继承(MI)时,程序可能从一个以上base classes继承相同名称(函数、typedef等),这会导致歧义:

  clas BorrowableItem{
    public:
        void checkOut();
        ……
    };
    class ElectronicGadgent{
    private:
        bool checkOut() const;
        ……
    };

    class MP3Player: public BorrowableItem, public ElectronicGadget
    {
        ……
    };
    MP3Player mp;
    mp.checkOut();//歧义,调用哪个checkOut

为了解决歧义,必须指明调用哪一个base class内的函数

mp.BorrowableItem::checkOut();

多重继承还可能会导致“钻石型多重继承”

class File{……};
    class InputFile: public File{……};
    class OutputFile: public File{……};
    class IOFile:public InputFile, public OutputFile
    {……};

在上面这个继承体系中,IOFile会有File的两重拷贝,因为InputFile和OutFile都有一份拷贝,而IOFile有这两个class的拷贝。假如File class有个成员变量fileName,那么IOFile内有两个这样的数据。IOFile继承base classes,所以应该有两份,但是这两个变量是重复的,fileName只需一份即可。

C++在是否需要2份拷贝的辩论中没有立场,两个方案它都支持,缺省方案是第一个方案。如果要用第二个方案,那么就要让带此数据的class(即File)成为一个virtual base class。


从正确行为的观点看,public继承应该总是virtual、如果这是唯一一个观点,那么任何时候当你使用public继承时,请改用virtual public继承。


2、但是,virtual继承会增加大小、速度、初始化(及赋值)复杂度等等成本,如果virtual base class不带任何数据,将是最具实用价值的情况

对virtual 继承的忠告:非必要不要使用virtual继承,平常请使用non-virtual继承;如果必须使用virtual继承,尽可能避免在其中放置数据。



3、多重继承的确有正当用途。其中一个情节设计“public继承某个类的接口”和“private继承某个协助实现的类”的组合

class IPerson{   //这个类指出需实现的接口
    public:
        virtual ~IPerson();
        virtual std::string name() const=0;
        virtual std::string birthDate() const=0;
    };
    class DatabaseID{……};//稍后被使用:细节不重要
    class PersonInfo{      //这个类有若干有用函数,可以以实现IPerson接口
    public:
        explicit PersonInfo(DatabaseID pid);
        virtual ~PersonInfo();
        virtual const char* theName() const;
        virtual const char* theBirthdayDate() const;
        ……
    private:
        virtual const char* valueDelimOpen() const;
        virtual const char* valueDelimClose() const;
        ……
    };
    class CPerson: public IPerson, private PersonInfo{ //多重继承
    public:
        explicit CPerson(DatabaseID pid): PersonInfo(pid){}
        virtual std::string name() const              //实现必要的IPerson成员函数
        {
            return PersonInfo::theName();
        }
        virtual std::string birthDate()
        {
            return PersonInfo::theBirthDate();
        }
    private:
        const char* valueDelimOpen() const{return "";}  //重新定义继承的virtual成员函数
        const char* valueDelimClose() const{return "";}
    };

多重继承只是面向对象的一个工具而已。和单一继承比较,它比较复杂,也难以理解,所以如果有一个单一继承方案和一个多重继承方案,那么单一继承方案比较受欢迎。但是如果通过多重继承可以完成任务,而且最简洁、最易维护、最合理,那么就不用怕使用它。



参考:http://blog.csdn.net/thefutureisour/article/details/7985263

            http://blog.csdn.net/KangRoger/article/details/44161773

            

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值