• C++继承、多态与虚函数(二)


    继承的对象,对象模型的查看

        继承会将基类中的所有成员保存到派生类中,如果一个基类有1个公用数据成员和1个私有数据成员,当使用任意一种继承方式时,派生类的对象都会把它们继承下来,占用的内存空间将是2。但是编译器将会阻止你访问基类的私有数据成员。

    开发人员如何利用命令提示符查看对象模型:

    1、跳转到程序存储的盘, F:

    2、跳转到文件路径,cd 具体路径

    3、查看命名,cl/d1 reportSingleClassLayout类名 文件名

    多态

    多态是C++面向对象三大特性之一,通常可以分为静态多态动态多态

    静态多态:函数重载和运算符重载属于静态多态,复用函数名。

    动态多态:派生类和虚函数实现程序运行时的多态。

    静态多态和动态多态的区别:静态多态的函数地址早绑定,编译截断确定函数地址;动态多态的函数地址晚绑定,运行阶段确定函数地址。

    动态多态的满足条件:

    1、必须有继承关系;

    2、派生类要重写基类的虚函数,例如下例中每个speak都不一样

    (重写:函数返回值类型、函数名称和参数列表完全相同)

    3、派生类中的virtual可写可不写。

    动态多态的使用:

    1. 基类的指针或引用执行子类的对象,例如void doSpeak(Animal &animal)
    1. #include<iostream>
    2. using namespace std;
    3. class Animal
    4. {
    5. public:
    6. virtual void speak()
    7. {
    8. cout << "The animal is speaking!" << endl;
    9. }
    10. };
    11. class Cat : public Animal {
    12. public:
    13. void speak()
    14. {
    15. cout << "The cat is speaking!" << endl;
    16. }
    17. };
    18. class Dog : public Animal {
    19. public:
    20. void speak()
    21. {
    22. cout << "The dog is speaking!" << endl;
    23. }
    24. };
    25. void doSpeak(Animal& animal)
    26. //如果想让猫说话,则这个函数地址不能提前绑定
    27. //需要在运行阶段进行绑定
    28. {
    29. animal.speak();
    30. }
    31. void test01()
    32. {
    33. Cat cat;
    34. doSpeak(cat);
    35. Dog dog;
    36. doSpeak(dog);
    37. }
    38. int main()
    39. {
    40. test01();
    41. }

    多态的原理

    多态的使用条件:父类指针或引用指向子类对象。

    Animal类的内部结构Cat类的内部结构

    class Animal

    {

    public:

             virtual void speak()

             {

                      cout << "The animal is speaking!" << endl;

             }

    };

    这时候animal会有一个4个bit大小的指针,这个指针叫做vfptr即virtual function pointer虚函数指针,这个指针会指向一个虚函数表vftable。

    在这个表内部记录了虚函数的地址,即speak函数的地址被记录在内,&Animal::speak

    class Cat : public Animal {

    public:

             void speak()

             {

                      cout << "The cat is speaking!" << endl;

             }

    };

    继承后,cat的vfptr会指向一个虚函数表,和父类是一样的表。

    但是如果发生了重写,那么子类会将继承下来的虚函数表进行覆盖操作,子类的虚函数表内部会被替换成子类的虚函数地址,即&Cat::speak

    因此当使用父类的指针或引用指向子类的对象时,会从子类的表中找到函数的地址,就发生了多态,即

    Animal &animal =cat;

    Animal.speak();

    纯虚函数和抽象类

    通常父类中的虚函数是用不到的,通常调用的都是子类中的函数。比如说我们没有让animal说话,指向让dog和cat说话。此时animal中的虚函数就是纯虚函数。

    纯虚函数的语法:virtual 返回值类型 函数名 (参数列表)=0;

    当类中有了纯虚函数,这个类也成为抽象类。

    抽象类的特点:无法实例化对象;子类必须重写抽象类中的纯虚函数,否则也属于抽象类。

    1. #include<iostream>
    2. using namespace std;
    3. class Base {
    4. public:
    5. virtual void func() = 0;
    6. //只要有一个纯虚函数,则这个类称为抽象类
    7. };
    8. class Son : public Base {
    9. public:
    10. //子类必须重写父类中的虚函数,否则无法实例化
    11. virtual void func()
    12. {
    13. cout << "func调用" << endl;
    14. }
    15. };
    16. void test01()
    17. {
    18. //Base d; 父类是抽象类,抽象类是无法实例化对象的
    19. Base* base = new Son;//new的是什么样的对象,调用的就是什么对象的成员
    20. //这样使用一个父类指针,就可以调用所有的子类成员。
    21. base->func();
    22. }
    23. int main()
    24. {
    25. test01();
    26. }

  • 相关阅读:
    OpenCL编程指南-10.2使用C++包装器API的矢量相加示例
    第16章-cpp string类和标准模板库
    MySQL作业一
    中原雄狮官网上线 | LTD物流服务行业案例分享
    Pytorch,矩阵求和维度变化解析
    Linux 中的 comm 命令及示例
    学生选课系统基础版
    MybatisPlus基本使用(MP快速上手)
    [运维|数据库] mysql的charset与PostgreSQL的encoding
    网站被攻击怎么办
  • 原文地址:https://blog.csdn.net/Lao_tan/article/details/125426489