继承与菱形继承

1.面向对象的程序设计的三大要素是封装、继承、多态。封装是用访问限定符将成员变量和成员函数包装,以实现不同权限的访问目的,访问限定符有public、protected、private。一般的将成员函数设为private,成员函数设为public或protected。
继承是面向对象复用的重要手段,子类继承父类,是两个类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。在继承关系里,派生类继承基类的成员,以此达到复用的目的。
多态就是多种形态,同样的一份代码,由于调用对象的不同,实现不同的结果。如同样是买票的函数,成人调用和儿童调用其结果不同。
2.继承关系:public(公有继承)、 protected(保护继承)、 private(私有继承)

这里写图片描述

三种继承关系下基类成员在派生类中的访问关系
这里写图片描述

小结:不论哪种继承方式,在派生类内部都可访问基类的公有成员和保护成员,只不过继承下来变为派生类的保护或私有成员而已。基类的私有成员存在但在子类中不可访问。保护限定符是因继承才出现的,如果基类成员不想被基类对象直接访问,但在派生类中能访问,那就定义为保护成员。大多数情况下,使用的都是public继承。

3.继承的赋值兼容规则

class Person
{
private:
    string _name;
};

class Student:public Person
{
private:
    int _num;
};

int main()
{
    Person p;
    Student s;
    //p = s;//子类对象可以赋值给父类对象(切片)

    s = p;//父类对象不能赋值给子类对象

    Person* p1 = &s;//父类的指针/引用可以指向子类对象
    Person& p2 = s;

    return 0;
}

4.单继承与多继承
在派生类中最好不要定义和基类中相同的函数,会构成隐藏(重定义),屏蔽基类中的同名函数。此概念不同于重写(在多态中)。在继承关系里面,编译器会默认合成六个默认成员函数,也就是说,以合成构造函数为例,派生类只初始化自己的成员,基类部分调用基类的构造。
这里写图片描述

5.菱形继承与菱形虚拟继承
这里写图片描述

class A
{
protected:
    int _a;
};

class B : public A
{
protected:
    int _b;
};

class C : public A
{
protected:
    int _c;
};

class D : public B,public C
{
protected:
    int _d;
};

int main()
{
    D d;
    d._a = 1;//菱形继承的二义性,不知道访问哪一个_a
    return 0;
}

这里写图片描述

菱形继承的二义性(数据冗余)问题:
D继承了B和C,B和C继承了A,B和C中都有变量_a,但D访问 _a时,不知道是访问B中的 _a还是C中的 _a。
解决:菱形虚拟继承(virtual)

class A
{
public:
    int _a;
};

class B :virtual public A
{
public:
    int _b;
};

class C :virtual public A
{
public:
    int _c;
};

class D :public B,public C
{
public:
    int _d;
};

int main()
{
    D d;
    d._a = 1;
    d._b = 2;
    d._c = 3;
    d._d = 4;
    return 0;
}

这里写图片描述
这样就解决了菱形继承的二义性和数据冗余的问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值