C++ 中的继承有 3 种方式,分别是 public、protected 和 private,这三种方式分别对应不一样的父类成员的访问权限,总结以下:java
这 4 条规则实际上只有第 2 条是经常使用的,下面说下这 3 种做用域的使用场景。ios
咱们常常会将子对象强制转换(casting)为父对象,而 public 继承在这种强制转换的场景下是无障碍的,这种状况下,子类对象能够理解为一种特殊的父类对象,即它们是一种 is-a 的关系;除此以外,其余的由 protected 或 private 做用域继承而来的对象就不具有这样的关系,下面是一个简单的例子:spa
#include <iostream>
using namespace std;
class B {
private:
int val_;
public:
B(int val) : val_(val) {}
void print_val() { cout << "val_ = " << val_ << endl; }
};
class D_pub : public B {
public:
D_pub(int val)
: B(val)
{}
};
class D_pro : protected B {
public:
D_pro(int val)
: B(val)
{}
};
int main() {
D_pub pub(1);
B* b = &pub;
b->print_val();
D_pro dpro(1);
B* b2 = &dpro; // error: 'B' is an inaccessible base of 'D_pro'
}
复制代码
上面例子中,类 B 是一个基类,D_pub 是一个使用 public 做用域的子类,而 D_pro 是使用 protected 做用域的子类,咱们在 main 中分别建立 D_pub 的对象 pub 和 D_pro 的对象 dpro,并分别赋值给父类指针,能够看到,将 D_pro 对象赋值给父类指针的语句报编译错误,缘由在于类 B 中的可访问成员在 D_pro 中变成了不可访问成员,即 D_pro 对象再也不是一个特殊意义的 B 对象,它们之间不具有 is-a 关系。以此类推,private 继承的子类和父类也没有 is-a 关系。指针
protected 和 private 继承相似于组合模式(composition),它是一种 has-a 关系,咱们看一个组合模式的例子:code
class hat {
public:
void wear() {}
};
class child {
hat h_;
public:
void hat_wear() { h_.wear(); }
};
复制代码
上面的代码中,child 类是以将 hat 组合进来的方式实现的,即让 child 类也具有 hat 的方法,一种很好的办法是将 hat 做为 child 的一个成员,从语义上,child 和 hat 具有 has-a 的关系。下面咱们看使用 protected 或 private 继承如何实现 has-a 的关系:对象
class child : private hat {
public:
using hat::wear; // 此时 child 对象就能够调用 hat::wear 方法了
};
int main() {
child c;
c.wear();
}
复制代码
咱们将 child 以 private 的方式继承自 hat,并将 hat::wear
方法放置在 child 的 public 做用域中,这样 child 就「拥有了 hat 的能力」,它们之间也是一种 has-a 关系。继承
虽然不一样的实现达到了相同的效果,但依然不建议使用 private 或 protected 的方式实现 has-a 的关系,而建议更多的使用组合模式,一是由于组合模式更为直观,其二是由于组合模式将组合的多个对象解耦(它们没有多一层继承关系),其三是组合模式更为灵活,试想一个类有多个组合对象的状况。作用域
以上,咱们介绍了 C++ 中继承的三种做用域,此时咱们须要记住 4 个规则:get
以及 2 个使用场景:it
参考:Advanced C++: Inheritance - Public, Protected, and Private