C++:私有继承
标签(空格分隔): c++
公有继承是一种is-a的关系,而包含是一种has-a的关系。使用公有继承,基类的公有方法将成为派生类的公有方法。总之,派生类将继承基类的接口,这是is-a关系的一部分。然而C++中提供了另外一种实现has-a的方式——私有继承1
私有继承
使用私有继承,其基类的公有方法将成为派生类的私有方法。总之,派生类不继承基类的接口。
要进行私有继承,应该使用关键字private而不是public来定义类。实际上private是默认的类继承关系:
class Student : private std::string{...};
初始化基类组件
隐式的继承组件而不是成员对象将影响代码的编写,因为再也不能使用name来描述对象了。而必须使用用于公有继承的技术。例如,对于构造函数:
Student::Student(const char*str):name(str){}
对于使用私有继承的构造函数则成了这个样子:
Student::Student(const char*str):std::string(str){};
访问基类方法
使用私有继承时,只能在派生类的方法中使用基类的方法。私有继承使得能够使用类名和作用域解析符来调用基类的方法:
double Student::average() const{
return Array::sum()/Array::size();
}
访问基类对象
使用作用域解析符可以访问基类的方法,但是如果要使用基类对象本省,就需要强制类型转换。由于Student类是从stirng派生而来,因此可以通过强制类型转换,将Student对象转换为string对象
const string & Student::Name() const{
return (const string &)*this;
}
访问基类友元函数
使用类名显式的限定函数名不适合于友元函数,这是因为友元不是类的成员。然而我们可以显式的转换为基类来正确的调用。
ostream & operator<<(ostream &os ,const Student &stu){
os<<(const string &)stu<<endl;
}
应该使用包含还是继承
对于has-a的关系,我们既可以使用包含去实现,也可以使用私有继承实现,那么我们应该使用继承还是包含?
大多数程序猿倾向于使用包含,因为这样代码层次清晰,耦合度比继承低,是一种良好的设计模式。并且,继承会引起许多的问题,尤其是从多个基类继承时,需要多次的转型操作。然而,私有继承提供的特性比包含多。另一种情况是私有继承需要重新定义虚拟函数。派生类可以重定义虚函数,但包含不可以。
保护继承
保护继承是私有继承的一种变体。保护继承在列出基类时使用了protect关键字:
class Student : protected std::string{...};
使用保护继承时,基类的公有成员和保护成员都成为派生类的保护成员。和私有继承一样,基类的接口在派生类中也是可用的,但是在继承层次结果之外是不可用的。
重新定义访问权限
当我们想要对外提供继承的方法时,可以采取两种方式
1,包装
double Student::sum() const{
return std::Array::sum();
}
2,使用using重定义
class Student : private std::Array{
...
public:
using std::Array::sum();
using std::Array::average();
...
};
各种继承方式的比较
特征 | 公有继承 | 保护继承 | 私有继承 |
---|---|---|---|
公有成员变成 | 派生类的公有成员 | 派生类的保护成员 | 派生类的私有成员 |
保护成员变成 | 派生类的保护成员 | 派生类的保护成员 | 派生类的私有成员 |
私有成员变成 | 不可访问 | 不可访问 | 不可访问 |
能够隐式向上转型 | 能 | 能(只能在派生类内部) | 不能 |
- Stephen Prata.C++ Primer Plus.人民邮电出版社.2016.3 543~550 ↩