类和继承

想要学好c++就必须掌握并熟练使用类,类有三大特性:封装,继承和多态。下来我们就深度剖析一下继承这个特性。
那什么是继承呢?
从字面意思来看,继承可能指的是一个类继承了什么东西,既然是继承它可能拥有这些东西和这些东西的特性。我们可以从下面的关系来看继承:
这里写图片描述
理解了继承的关系后正式引出继承的概念:
继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
继承的定义格式:
这里写图片描述
重点看一下继承类型:
这里写图片描述
从实例看一下访问类型的差异:

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
class Base
{
public:
    Base()
    {
        cout<< "Base()" << endl;
    }
    ~Base()
    {
        cout << "~Base()" << endl;
    }
private:
    int _b1;
protected:
    int _b2;
public:
    int _b3;
};
class Derived:protected Base
{
public:
    Derived()
    {
        cout<< "Derived()" << endl;
    }
    ~Derived()
    {
        cout<< "~Derived()" << endl;
    }
private:
    int _d1;
protected:
    int _d2;
public:
    int _d3;
};
int main()
{
    Derived d;
    d._b3;
    d._d3;
    system("pause");
    return 0;
}

测试结果:
这里写图片描述
通过上述代码及其测试结果我们可以总结:
1. 基类的private成员在派生类中是不能被访问的,如果基类成员不想在类外直接被访问,但需要在派生类中能访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。
2. public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
3. protected/private继承是一个实现继承,基类的部分成员并非完全成为子类接口的一部分,是 has-a 的关系原则,所以非特殊情况下不会使用这两种继承关系在绝大多数的场景下使用的都是公有继承。私有继承以为这is-implemented-interms-of(是根据……实现的)。通常比组合(composition)更低级,但当一个派生类需要访问基类保护成员或需要重定义基类的虚函数时它就是合理的。
4. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,基类的私有成员存在但是在子类中不可见(不能访问)。
5. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
6. 在实际运用中一般使用都是public继承,极少场景下才会使protetced/private继承.
派生类的默认成员函数:
在继承关系里面,在派生类中如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数。
这里写图片描述
【继承关系中构造函数的调用顺序】
派生类中对象构造函数–》基类构造函数–》派生类构造函数体
【继承关系中析构函数的调用顺序】
派生类析构函数–》派生类包含成员对象析构函数–》基类析构函数
【继承体系中的作用域】
1. 在继承体系中基类和派生类是两个不同作用域。
2. 子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)–隐藏 –重定义
3. 注意在实际中在继承体系里面最好不要定义同名成员。
【继承与转换–赋值兼容规则–public继承】
1. 子类对象可以赋值给父类对象(切割/切片)
2. 父类对象不能赋值给子类对象
3. 父类的指针/引用可以指向子类对象
4. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)
【友元与继承】
友元关系不能继承,也就是说基类友元不能访问子类私有和保护成员。
【继承与静态成员】
基类定义了static成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例。
【单继承&多继承&菱形继承】
单继承:一个子类只有一个直接父类时称这个继承关系为单继承。
这里写图片描述
多继承:一个子类有两个或以上直接父类时称这个继承关系为多继承
这里写图片描述
菱形继承:
这里写图片描述
【菱形继承对象模型】
这里写图片描述
我们可以看到D对象中有两份A的成员,菱形继承存在二义性和数据冗余问题。
【虚继承–解决菱形继承的二义性和数据冗余的问题】
1. 虚继承解决了在菱形继承体系里面子类对象包含多份父类对象的数据冗余&浪费空间的问题。
2. 虚继承体系看起来好复杂,在实际应用我们通常不会定义如此复杂的继承体系。一般不到万不得已都不要定义菱形结构的虚继承体系结构,因为使用虚继承解决数据冗余问题也带来了性能上的损耗。
那怎么实现虚拟继承呢?
这里写图片描述
原理是什么呢?
实现了虚拟继承后编译器会在合成子类的构造函数里填写偏移量表格地址。
什么是偏移量表格地址呢?
【虚拟继承的对象模型】
这里写图片描述
虚拟继承后A(父类)的成员就只保留一份,可以通过D(子类)的对象来访问。(类似于父类的静态成员,但又区别于静态成员。)
我们看下面的代码:

#include <stdio.h>
using namespace std;
class Person
{
public:
    string _name;

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

};
class Teacher :public Person
{
protected:
    int _id;
};
class Assistant : public Student, public Teacher
{
protected:
    string _majorCourse;
};
void Test()
{
    Assistant a;
    a.Student::_name = "xxx";//访问Student成员_name
    a.Teacher::_name = "yyy";//访问Teacher成员—name
}
int main()
{
    Test();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值