关于private继承

在C++的类中有许多种继承方式,而我们在软件设计和编写代码时用得最多的就是public继承,我们很少接触到private继承。但是我们在设计时真的有思考过什么时候应该用public继承,什么时候不该使用public继承,什么时候应该想想那些经常被我们遗忘的知识,让我们从它们被遗忘的角落里重拾它的光芒。例如private继承。


As we all know,public继承是塑模出一种is-a关系。什么是is-a的关系呢?Effective C++这样描述:如果你令class D以public形继承class B,那么每一个类型为D的对象同时也是一个类型为B的对象,反之不成立。意思是B比D表现出更一般化的概念,而D比B表现出更特殊化的概念。你主张“B对象可派上用场的地方,D对象一样可以派上用场”,因为每一个D对象都是一种(是一个)B对象。反之如果你需要一个D对象,B对象无法效劳。

还有就是我们喜欢用的virtual函数,即运行动态也是建立在public继承之上的。

在我刚学C++时,只知道private继承,使继承而来的成员(public成员和protected成员)都成为private,至于它有没有什么更深一层的意义和作用就没有去思考了,只是理想当然地把它认为是不想这些成员被它的以后的子类继承。那private继承到底意味着什么呢?

先看看下面的代码:
class Person{...};
class Student:private Person{...};
void eat(const Person &p);
Person p;
Student s;
eat(p);//正确
eat(s);//错误

再看看Effective C++的说法:
如果classes之间的继承关系是private,编译器不会自动将一个deirved class对象转换为一个base class对象。
private继承意味着implemented-in-terms-of(根据某物实现出)。如果你让class D以private继承class B,你的用意是为了采用class B内已经备妥的某些特性,不是因为B对象和D对象存在有任何观念上的关系。private继承纯粹是一种实现技术,意味着只有实现部分被继承,接口部分应该略去。如果D以private形式继承B,意思是D对象根据B对象实现而得,private继承在软件设计层面上没有意义,其意义只及于软件实现层面。

private有点has-a的感觉。它的意义与复合的意义相同。那我们的问题又产生了,什么时候用复合什么时候用private继承?答案很简单,尽可能使用复合。除了以下的2种情况:
1、private继承通常比复合的级别低。但是当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,就要用private继承。
2、private继承可以造成empty class最优化。

#include <iostream>
using namespace std;
class Base
{
public:
    void Bfun1(){cout << "I'm Bfun1()" << endl;}
protected:
    void Bfun2(){cout << "I'm Bfun2()" << endl;}
private:
    void Bfun3(){cout << "I'm Bfun3()" << endl;}
};
class Derived : private Base
{
public:
    void Dfun1() {cout << "I'm Dfun1()  " ;Bfun1();}
    void Dfun2() {cout << "I'm Dfun2()  " ;Bfun2();}
};
int main()
{
    Derived d;
    d.Dfun1();
    d.Dfun2();

    //d.Bfun1();
    //d.Bfun2();
   // d.Bfun3();
    return 0;
}

运行后我们可以发现:1)派生类对象d是无法访问基类的任一成员函数的(包括public成员函数),因为这是private继承

                                        2)派生类本身是能访问基类的public 和protected成员的,如Dfun1函数访问了Bfun1   Dfun2函数访问了Bfun2;


二、关于《Effective c++》中Item 39

1、如果类之间的关系是private继承,则:a:编译器不会自动将一个派生类对象转换成一个基类对象  b: 基类中的所有成员在派生类中都编程private属性,派生类对象无法访问

2、private表现出的关系是“根据某物实现出”,它继承的是实现而非接口

     乍看很奇怪,实现都继承了怎么接口都不继承。这样理解,我们派生类需要利用private 基类中的一些成员实现某些东西,但是成员经过继承后变成了private属性,用户是无法通过接口访问它的,所以只是继承了实现而忽略了接口。

3、private继承主要用于:当两个类不存在“is-a”的关系,其中一个需要访问另一个的protected成员,或需要重新定义一个或多个virtual函数

这句话这么理解:现有两个类并非“is-a”关系,类D需要用类B的一些成员去实现它,而且我要用到的这些成员往往是类B的protected成员或者是虚函数。但是我只是需要这些成员去实现我的类D,并不给用户提供接口能直接访问类B的这些成员,这时候就应该用private继承。

我们看一个例子吧,这是Item 40改编过来的。

我希望实现一个类CPerson 它能提取人的name 和 birthdate,我想偷个懒,发现有这么一个类PersonInfo能实现差不多的功能,只是Person的格式有点不符合我的要求,我就打算利用PersonInfo来实现我Cperson的name函数和birthdate函数。

class PersonInfo{
	public:
		explicit PersonInfo(DatabaseID pid);
		virtual ~PersonInfo();
		virtual const char* theName() const;
		virtual const char* theBirthDate() const;
		...
	private:
		virtual const char* valueDelimOpen() const{return "["};	//“开始”符号,用于姓名的输出
		virtual const char* valueDelimClose() const{return "]"};	//“结束”符号
		...
};
const char* PersonInfo::theName() const{
	static char value[Max_Formatted_Field_Value_Length];	//保留缓冲区给返回值使用。注意由于缓冲区是static的,会被自动初始化为“全部是0”
	std::strcpy(value, valueDelimOpen());	//写入起始符号
	...	//添加姓名
	std::strcat(value, valueDelimClose());	//写入结束符号
	return value;
}
class CPerson : private PersonInfo{
public:

    std::string name()const
    {return PersonInfo::theName();}

    std::string birthDate()const
    {return PersonInfo::theBirthDate();}
private:
    virtual const char* valueDelimOpen() const{return ""};
    virtual const char* valueDelimClose() const{return ""};
    ...
};

我们发现:a:类CPerson的name通过调用类PersonInfo的成员函数实现,我这里用了它的实现,却没有给用户提供调用类PersonInfo成员的接口(因为是private继承)

                    b:由于PersonInfo的格式不符合我的要求,(它是用的方括号[    ],我却不想要方括号),而控制格式的是两个虚函数valueDelimOpen  valueDelimClose  这里我就可以重定义virtual函数了,在Cperson中,我们重定义了上述两个控制格式的函数。  这就是上面说的“需要重新定义一个或多个virtual函数”的情况


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值