【cpp进阶-01】谈谈多态问题

前言

继承、封装、多态是面向对象的三大特性。
本文主要介绍一些多态的细节来深入cpp。

静态多态

重载

重载函数

  1. 定义:

    在作用域范围内有多个名称相同但参数签名不同的函数

  2. 注意:

    (1)返回值不能作为重载的判断依据

    (2)派生类不能重载基类的同名函数,会遮蔽掉基类的函数

  3. 底层实现:

    cpp在编译时会根据命名空间、类、参数类型进行名字编码,形成新的函数名,重载的不同函数便有不同的函数地址入口。

重载运算符

operator 运算符名称看作函数进行重载

  1. 成员函数的重载 与 全局函数的重载 选择

    +,-,*,/,==,!=建议全局重载

    +=,-=,*=,/=建议成员重载

  2. 原因:转换构造函数

    Complex{
    ...
    friend Complex operator+(const Complex &c1, const Complex &c2);
    ...
    }
    
    //友元+全局函数
    Complex operator+(const Complex &c1, const Complex &c2){
        return Complex(c1.m_real + c2.m_real, c1.m_imag + c2.m_imag);
    }
    
    Complex c = Complex(1.0) + 2.0; //true: const&:允许引用右值;自动类型转换。 
    

模板与泛型

参数推断

定义时不指明参数类型,调用时通过实参进行推断。

关键字:template<typename T>

动态多态

继承与虚函数

  1. 为什么 基类的指针指向派生类对象,成员变量是派生类的,而成员函数是基类的?

    根据cpp对象的内存模型解释:

    (1)成员变量:对象独有,与对象(派生类对象)绑定;

    (2)成员函数:类共享,预处理时根据类型,参数列表等重新命名函数,与类(基类)绑定;

  2. 为什么 虚函数可以解决上述问题?

    每个对象内存中存在一个虚函数表的指针,调用函数时通过派生类对象的虚函数指针调用正确的函数。

  3. 为什么 构造函数不能是虚函数?

    (1)构造函数无法继承,虚函数没有意义。

    (2)构造函数用于初始化,创建对象未完成,虚函数表指针尚未初始化,无法查询虚函数表调用正确的构造函数。

  4. 为什么 析构函数使用虚函数?

    (1)若派生类在基类的基础上多生产了指针,使用了空间,不使用虚析构函数会导致部分空间不能被释放,内存泄漏

  5. 解释一下虚函数表的内存模型

(1)每一种类型独有一种虚函数表

(2)如果派生类的同名虚函数遮蔽了基类的虚函数,将表中的函数进行替换

(3)对象创建时在开头生成虚表指针指向类型的虚函数表

  1. 纯虚函数 和 抽象类

    (1)virtual = 0表示纯虚函数

    (2)抽象类无法实例化