这篇主要对继承类型和菱形继承问题做一个笔记。
1. 继承类型
继承类型有公有、保护和私有。
1.1 公有继承
公有继承可以继承父类中public和protected的成员与方法,是最简单的方式,如下表:
父类中的成员: | public | protected | private | 能否隐式向上转换 |
---|---|---|---|---|
子类中: | 可以访问,成为子类的public | 可以访问,成为子类的protected | 不能访问,只能通过父类的函数接口访问 | 可以 |
其中隐式向上转换即能否用父类指针管理子类对象。
1.2 私有继承
如果我们想将另一个类(例如vector)作为这个类的一个成员, 最简单的方式是:
class A{
private:
std::vector<int> arr;
...
public:
int getValue(int pos) { return arr[pos]; }
}
这种方式直观好用. 但如果设想这么一个情形: 假设我们作为成员的那个类有一个protected成员, 而且我们想访问它. 那么我们通过以上的方式是做不到的. 这时,我们可以通过private继承的方式:
class A : private std::vector<int>{
private:
...
public:
A(std::vector<int> v) : std::vector<int>(v) {}
int getValue(int pos) { return std::vector<int>::at(pos); }
}
来访问到protected的成员.
当然at方法不是vector的protected成员, 只是举个例子
private的性质如下表:
父类中的成员: | public | protected | private | 能否隐式向上转换 |
---|---|---|---|---|
子类中: | 可以访问,成为子类的private | 可以访问,成为子类的private | 不能访问,只能通过父类的函数接口访问 | 不可以 |
1.3 保护继承
保护继承的大部分行为应该与私有继承差不多, 但是当该类再派生类的时候, 就体现出区别了. 也就是说, 如果是私有继承, 则第一代类的成员到了第二代类都成了私有的, 因此第三代类无法访问. 而如果是保护继承, 则第一代类的成员到了第二代类仍然是保护的,所以到第三代类也能访问. 具体如下表:
private的性质如下表:
父类中的成员: | public | protected | private | 能否隐式向上转换 |
---|---|---|---|---|
子类中: | 可以访问,成为子类的protected | 可以访问,成为子类的protected | 不能访问,只能通过父类的函数接口访问 | 可以 |
2. 菱形继承问题
菱形继承问题主要就是当一个类继承多个类, 而继承的多个类拥有共同的祖先, 则在该类中就会存在多个祖先的副本, 从而在访问祖先的成员时造成二义性.
假设我们有一个Restaurant类, 有一个KFC类和McDonald类分别继承它. 然后再有一个Wallace类同时继承KFC和McDonald, 就会是这样的结构:
那么当我们实例化Wallace的时候, 就要分别调用KFC和McDonald的构造函数, 而KFC和McDonald又会分别构造一个Restaurant, 于是Wallace里面就成了这个样子:
所以它里面有两个Restaurant, 当然会产生二义性了.
解决这个问题的方法是使用虚继承, 或者说把最远的基类变成虚基类. 当一个类被虚继承时, 它就成了虚基类. 为了避免有两个Restaurant, 一个直观的办法是, 我们在构造Wallace的时候, 在构造McDonald和KFC的时候不构造Restaurant, 而另外构造一个Restaurant, 这样每个类在Wallace中只有一份, 事实上如果使用虚继承, 则编译器就是这样做的.
因此, 在构造Wallace类的时候, 不像普通继承那样只需要写父类的构造函数就行了, 这时必须要写父类的父类(Restaurant类)的构造函数, 这样才能达到每个祖宗都是一份的效果.
例如下面的示例:
class Restaurant{
private:
std::string name;
int price;
public:
Restaurant(std::string str, int p) : name(str), price(p) {};
virtual ~Restaurant() {} ;
virtual void getName() { std::cout << name << price << "\n"; };
int returnPrice() { return this->price; };
};
class KFC : virtual public Restaurant{
private:
bool crazyThursday;
public:
KFC(std::string str, int p, bool cT) : Restaurant(str, p), crazyThursday(cT) {};
virtual ~KFC() {};
virtual void getName() { this->Restaurant::getName(); std::cout << this->crazyThursday << "\n"; };
};
class McDanolds : virtual public Restaurant{
private:
int OMCard;
public:
McDanolds(std::string str, int p, int OMCard_) : Restaurant(str, p), OMCard(OMCard_) {};
virtual ~McDanolds() {};
virtual void getName() { this->Restaurant::getName(); std::cout << this->OMCard << "\n"; };
};
class Wallace : public KFC, public McDanolds{
private:
bool PensheSuperman;
public:
Wallace(std::string str, int p, bool cT, int OMCard_, bool ps) : Restaurant(str, p), KFC(str, p, cT), McDanolds(str, p, OMCard_) {};
void getName() { this->Restaurant::getName(); std::cout << this->PensheSuperman << "\n"; };
int getPrice() { return this->Restaurant::returnPrice();};
};
void func(){
std::string str = "asdadasdw";
Wallace w (str, 2, true, 2333, true);
std::cout << w.getPrice();
}
输出结果:
2