[杂记]关于C++中类继承的一些理解

这篇主要对继承类型和菱形继承问题做一个笔记。

1. 继承类型

继承类型有公有、保护和私有。

1.1 公有继承

公有继承可以继承父类中public和protected的成员与方法,是最简单的方式,如下表:

父类中的成员:publicprotectedprivate能否隐式向上转换
子类中:可以访问,成为子类的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的性质如下表:

父类中的成员:publicprotectedprivate能否隐式向上转换
子类中:可以访问,成为子类的private可以访问,成为子类的private不能访问,只能通过父类的函数接口访问不可以

1.3 保护继承

保护继承的大部分行为应该与私有继承差不多, 但是当该类再派生类的时候, 就体现出区别了. 也就是说, 如果是私有继承, 则第一代类的成员到了第二代类都成了私有的, 因此第三代类无法访问. 而如果是保护继承, 则第一代类的成员到了第二代类仍然是保护的,所以到第三代类也能访问. 具体如下表:
private的性质如下表:

父类中的成员:publicprotectedprivate能否隐式向上转换
子类中:可以访问,成为子类的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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值