明智而审慎的使用private继承
private继承的意义在于“be implemented in turns of”。
private继承与public继承时完全不同的,主要体现在两个地方
其一,public继承在子类中保持父类的访问权限,即父类中是public的成员函数或者成员便变量可,在子类中仍是public,对private或protected 的成员函数或成员变量亦是如此;但private继承则不是这样的,他破坏了父类红的访问权限标定,将之转成为private,这对子类本省并无影响,但却影响了子类的子类,子类的子类将无法访问这些声明/定义在爷爷辈类的成员变量或成员函数。
其二,Liskov法则不再使用,也就是“一切父类出现的地方都可以被子类替代”的法则在private这里不成立
#include <iostream> using namespace std; class Person{}; class Student:private Person {}; void eat(const Person& p){} int main() { Person p; Student s; eat(p); //ok eat(s); //false }
但如果令Student公有继承Person,则编译器不会报错。这正是Liskov的可替代原则在private继承中不适用的体现。
private继承使用的地方实在不多,除非有一些奇葩的设计需求
class TypeDefine {}; class SimpleClass{ int a; TypeDefine obj; }; class SimpleDerivedClass:private TypeDefine { int a; }; int main() { cout<<sizeof(TypeDefine)<<endl; cout<<sizeof(SimpleClass)<<endl; cout<<sizeof(SimpleDerivedClass)<<endl; }
第一个类是空类,仅仅是名字的空,看起来是空的,但其实不是这样子的,对于空类,编译器会位子生成默认的函数:默认构造函数,默认拷贝构造函数,,默认析构函数,默认赋值操作符,虽然函数不占空间,但类的每一个对象都须有一个独一无二的内存地址,所以空类的sizeof算出的值是1.非空类因为已经有了成员变量,所以编译器可以利用这些成员变量来进行内存地址的区分,从而表示类的不同对象。
第二个输出的是8,int 4字节再加到空类对象的四字节,理论上编译器还会做一种内存对齐的操作,使得类对象的大小是处理字长的整数倍
第三个输出时4,这其实是编译器做了空白基类优化,原本是要为空白类的对象插入一字节,但因为子类中已经有了对象了,这样理论上就可以凭借这个对象来进行同一个类不同间的识别了,所以这时候编译器就不再插入字节了。
这个结果就是用private继承的好处。