C++面向对象继承相关知识点总结

389 阅读2分钟

1 继承的基本语法

class 子类:继承方式 父类

子类也称为派生类;父类也称为基类。

继承的好处:可以减少重复的代码

派生类中的成员,包含两大部分:

  • 从基类继承过来的
  • 自己增加的成员

从基类继承过来的表现其共性,而新增的成员体现了其个性

2 继承方式

继承一共有三种方式:

  • 公共继承
  • 保护继承
  • 私有继承

image.png

3 继承中的对象模型

父类中的隐藏信息只是被编译器隐藏了,子类访问不到,但是还是会被继承的

#include<iostream>
using namespace std;
class Base
{
public:
    int m_A;
protected:
    int m_B;
private:
    int m_C;//父类中的私有属性只是被编译器隐藏了,不可以访问,但是还是被继承了
};
class Son:public Base
{
public:
    int m_D;
};
int main()
{
    cout<<"size of son= "<<sizeof(Son)<<endl;//16
    return 0;
}

4 继承中构造和析构顺序

创建一个子类对象,是会有一个父类对象的创建的,那么其顺序是如何的呢?

构造顺序:

  1. 先构造父类
  2. 再构造子类

析构顺序与构造的顺序相反

5 继承同名成员处理方式

当子类和父类出现同名成员时,如何通过子类对象,访问的子类或者父类中同名的数据呢?

方法:

  • 访问子类同名成员,直接访问即可
  • 访问父类同名成员,需要加作用域
#include<iostream>
using namespace std;
class Base
{
public:
    Base(){
        m_A=100;
    }
    void func(){
        cout<<"Base func"<<endl;
    }
    void func(int a){
        cout<<"Base func (int a)"<<endl;
    }
    int m_A;
};
class Son:public Base
{
public:
    Son(){
        m_A=200;
    }
    void func(){
        cout<<"Son func"<<endl;
    }
    int m_A;
};
//同名成员属性的处理方式
void test01(){
    Son s;
    cout<<s.m_A<<endl;//200
    cout<<s.Base::m_A<<endl;//100
}
//同名成员函数的处理方式
void test02(){
    Son S;
    S.func();//直接调用,调用的是子类中的同名成员
    S.Base::func();//调用父类中的同名成员函数
    //S.func(100); 错误,因为子类中出现和父类同名的成员。子类的同名成员会隐藏掉父类中所有同名成员函数
    S.Base::func(100);//还是得加作用域
}
int main()
{
    test01();
    test02();
    return 0;
}

6 继承同名静态成员处理方式

同名静态成员处理方法和非静态处理一样,只不过有两种访问方式(通过对象、通过类名)

#include<iostream>
using namespace std;
class Base
{
public:
    static int m_A;
    static void func(){
        cout<<"Base-static func()"<<endl;
    }
};
int Base::m_A=100;
class Son:public Base
{
public:
    static int m_A;
    static void func(){
        cout<<"Son-static func()"<<endl;
    }
};
int Son::m_A=200;
//同名静态成员属性
void test01()
{
    //1.通过对象访问
    Son s;
    cout<<s.m_A<<endl;
    cout<<s.Base::m_A<<endl;
    //2.通过类名访问
    cout<<Son::m_A<<endl;
    cout<<Son::Base::m_A<<endl;//第一个::代表类名访问方式,第二个::代表访问父类作用域下
}
//同名静态成员函数
void test02()
{
    //1.通过对象调用
    Son S;
    S.func();
    S.Base::func();
    //2.通过类名调用
    Son::func();
    Son::Base::func();
}
int main()
{
    test01();
    test02();
    return 0;
}

7 多继承语法

C++允许一个类继承多个类

语法:class 子类:继承方式 父类1,继承方式 父类2...

多继承可以会引发父类中有同名成员出现,需要加作用域区分。C++实际开发中不建议采用多继承

8 菱形继承

菱形继承的概念:

  • 两个派生类继承同一个基类
  • 又有某个类同时继承着两个派生类
  • 这种继承被称为菱形继承,又叫钻石继承

菱形继承的问题:

  • 会产生二义性
  • 孙子继承了爷爷两份数据,但其实我们只需要一份这样的数据就可以

我们可以利用虚继承来解决菱形继承的问题

#include<iostream>
using namespace std;
class Animal
{
public:
    int m_Age;
};
//继承前加virtual关键字后,变为虚继承
//此时公共的父类Animal称为虚基类
class Sheep:virtual public Animal{};
class Tuo:virtual public Animal{};
class SheepTuo:public Sheep,public Tuo{};
​
void test01()
{
    SheepTuo st;
    st.Sheep::m_Age=18;
    st.Tuo::m_Age=28;
    cout<<st.Sheep::m_Age<<endl;//28
    cout<<st.Tuo::m_Age<<endl;//28
    cout<<st.m_Age<<endl;//28
}
int main()
{
    test01();
    return 0;
}

其实质是这样的:

JZ5W8UENFV7)ELHX(E%02ST.png

Sheep和Tuo类只是继承了基类的需基类指针(vbptr),会指向自身的虚基类表(vbtable),根据表格所记录的偏移量,指向属性,这样就只是继承了一份数据,解决了菱形继承的问题。

参考链接

www.bilibili.com/video/BV1et…