版权声明:本文为CSDN博主「小码农丨」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
1.对比
特征 | 公有继承 | 保护继承 | 私有继承 |
---|---|---|---|
公有成员变成 | 派生类共有成员 | 派生类受保护成员 | 派生类私有成员 |
受保护成员变成 | 派生类受保护成员 | 派生类受保护成员 | 派生类私有成员 |
私有成员变成 | 派生类只能通过基类接口访问 | 派生类只能通过基类接口访问 | 派生类只能通过基类接口访问 |
能否隐式向上转型 | 是 | 是(只能在派生类中) | 否 |
2.公有继承
表示了两个类有is-a的关系,我的另一篇博客介绍了公有继承,这里不再说明。
3.私有继承
表示了两个类有has-a的关系;对于私有继承,基类的public接口到了派生类变成了private,则,派生类不会对外提供基类的接口,这就是说私有继承是has-a关系的原因
I>.初始化
同样的,在调用派生类构造函数之前,要先调用基类构造,如果缺省成员初始化列表,调用基类的默认无参构造
class A {
int a;
public:
A(int a = 0) : a(a) { cout << "A::A()" << endl; }
};
class B : private A{
public:
B(int a) : A(a){
cout << "B::B()" << endl;
}
};
II>使用基类
i>基类成员
私有继承中,可以将基类当作是一个未命名的子对象成员,可以通过强制类型转换“给这个对象命名”
class B : private A{
private:
A & obja = (A &)*this;
public:
B(int a) : A(a){
cout << "B::B()" << endl;
}
void f() {
obja.f();
}
};
通过一个基类引用给基类命名,这样,就相当于是B中声明了一个a的子对象;对于obja来说,他是一个基类对象,他可以调用基类的接口
当然,对于公有继承,也可以这样做,但是共有继承对外提供基类接口,不是has-a的关系,这样做并没有意义。
ii>基类方法
第一种访问方式就是通过上面的给基类成员命名的方式。
接下来介绍第二种方式
对于基类的方法,在派生类中变为了private,所以,在类外,是无法访问的,但是在派生类中,仍然可以访问(类内可以访问自己的私有)。
class B : private A{
public:
B(int a) : A(a){}
void f(){
A::f();//这里必须有域解析运算符,否则被认为是递归
}
};
III>关于向上转型的问题——不能隐式的转型
可以显式地转换,这里必须强制类型转换,否则会报错
int main() {
A *pa = (A*)new B(3);
pa->f();
return 0;
}
这里认真讨论一下
这里地B对象被当作一个A的实例化对象。因此,f()是否可以访问与f()在A中声明的访问权限有关
f()为非虚函数
采用静态联编
f()为虚函数
采用动态联编,pa指向了B对象,所以会调用B::f();这里不关心B::f()的访问权限,因为在pa指针看来,只能通过虚函数表来调用函数,权限信息是A::f()的权限,所以,如果基类f()为公有,不论派生类f()的访问权限是什么,都可以访问。但是,如果用B的指针来指,就会有访问权限限制。
这里虽然必须用显式地方法向上转型,但是和公有继承有很多共通之处
4.保护继承
保护继承与私有继承一样,同样不为外部提供接口,同样可看作has-a关系
主要说一下保护继承和私有继承地区别
对于接口来说,私有继承无法访问间接基类的接口,而保护继承在继承链中,可以访问所有基类的接口。
私有继承将基类接口变为私有,则再次派生时,就会变得不可见。
最后强调一点
虽然说私有继承和保护继承建立了has-a的关系,但是不同于直接的子对象包含,继承仍然有继承的一些特性,比如说虚函数。
5.通过using重新定义访问权限
class B : private A{
public:
using A::f;//相当于在B中声明了函数f,访问权限为public
};
使用using声明重新定义派生类可以访问的成员的访问权限。这 样,就相当于在B中相应的访问权限区域声明。
注意:派生类如果不可以访问,则不能修改权限,也就是说,不能修改派生类中的私有成员的访问权限。甚至可以将protected成员变成公有
class A {
protected:
int a;
public:
A(int a = 0) : a(a) {}
void f() {
cout << "A::f() ------ a = " << a << endl;
}
};
class B : private A{
public:
B(int a) : A(a){
cout << "B::B()" << endl;
}
using A::a; //派生类可以访问受保护,所以可以改变访问权限
using A::f;
};
int main() {
B obj(1);
obj.f();
cout << obj.a << endl;
return 0;
}