C++中继承详解

一、引言

    概念:是面向对象程序设计是代码可以复用的最重要的手段,它允许程序员在保持原有的类的特性的基础下进行拓展,增加功能。

    这样产生的类被称为派生类;

二、基本概念

    当一个类被其他的类继承时,被集成的类称为基类,也称作父类;

    继承父类的类称为派生类,也称作子类;

    继承类格式:

    派生类的名字:继承权限  父类的名字-->继承列表

class Derived : public Base

{}

//Base:基类  父类

//Derived:派生类  子类

继承权限对应于访问限定符可以分为三种:

public    protected    private

C++中继承详解_第1张图片

需要注意的是:在

class中:缺省的继承权限为private

struct中:缺省的继承权限为public

 

在这里不得不提的一点就是对象模型:

对象中成员变量在内存中的布局形式(非静态成员变量)

 

三、赋值兼容规则:public的继承方式

    子类与基类的关系 is-a:子类对象可以看成是一个基类对象;

1.子类对象可以给父类对象赋值

2.父类对象不能赋值给子类对象

3.父类对象的指针/引用可以指向子类对象

4.子类的指针/引用不能指向父类对象(强制类型转换)

class Person

{

public:

      /*void Display()

      {

            cout << _name << endl;

      }*/

protected:

      string _name;

};

class Student : public Person

{

public:

      int _num;

};

void Test()

{

      Person p;

      Student s;

      //1.子类对象可以给父类对象赋值

      p = s;

      //2.父类对象不能赋值给子类对象

      //s = p;

      //3.父类对象的指针/引用可以指向子类对象

      Person *p1 = &s;

      Person &r1 = s;

      //4.子类的指针/引用不能指向父类对象(强制类型转换)

      Student *p2 = (Student*)& p;

      Student &r2 = (Student&)p;

      p2->_num = 10; //(访问出错)

      r2._num = 20;

}

protected/private的继承方式:

    子类与基类的关系 has-a:相当于在派生类中内嵌了一个私有的基类;

class Base;

class Derived 

{

private:

    Base _b;

}

 

四、同名隐藏:

在基类和派生类中,具有相同名称的成员(成员函数||成员变量),如果用派生类对象去访问继承体系中的同名成员,只能访问到自己的,基类的成员无法访问;

只能通过加基类作用域的方式去访问相同成名的基类成员;

且优先给派生类中自己的成员变量和成员函数赋值;

 

五、派生类的默认成员函数:

    继承体系下,派生类若没有显示定义这六个默认成员函数,编译器会合成这六个默认的成员函数;

 

    生成:不依赖于任何东西,只是编译器根据简单的类的定义生成基于基础类型的默认成员函数;

    合成:必须依赖于基类,编译器根据基类的相应的成员函数的行为来合成派生类的默认成员函数;

 

1)继承体系中,派生类对象的构造函数:

派生类的构造函数,在进入派生类函数体中,先要在初始化列表中完成派生类中成员的初始化,先初始化基类中成员(构造成功:调用基类的构造函数),再初始化派生类自己的;

2)继承体系中,派生类对象的析构函数:

如果要销毁派生类的对象,则需要调用派生类析构函数来清理派生类对象,在派生类析构函数最后需要调用基类的析构函数已完成基类部分资源的释放;

 

友元关系:不能被继承,因为友元函数不是类的成员;

静态成员变量: 可以被继承,且是同一个变量;

 

六、派生类的对象模型

单继承:一个子类只有一个直接父类的继承关系;

 

多继承:一个子类有两个或以上直接父类的继承关系;

 

菱形继承:如下图

C++中继承详解_第2张图片

可以从菱形继承的对象模型中看出,Assistant类中存在两个Person对象,会存在数据冗长和二义性的问题;

C++中继承详解_第3张图片

 

如下面代码:

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";

      a.Teacher::_name = "yyy";

      a._name = "zzz";//错误:a对象中的_name不明确;

}

解决方法:虚拟继承

    虚拟继承:在继承权限的前面加上 virtual关键字即可构成虚拟继承;

    其特点是:在任何派生类中的virtual基类总用同一个(共享)对象表示;

 

该共享的对象并不是直接储存到派生类对象中去,而是存在一个指针指向各自的偏移量表,然后再从偏移量表中取得该共享对象的地址加以使用;

C++中继承详解_第4张图片

但注意,在实际应用中尽量不要设计菱形继承。

 

 

 

你可能感兴趣的:(C++中继承详解)