• 多态的定义 以及 虚函数重写(覆盖)


    多态指的是 父类和子类在执行相同行为的时候,出现了不同的结果。而虚函数是实现多态的重要条件之一。下面以Person类和Student类来了解多态。

    1. class Person {
    2. public:
    3. virtual void BuyTicket() { cout << "买票-全价" << endl; }
    4. };
    5. class Student : public Person {
    6. public:
    7. // 子类的 virtual 可以不写,但是父类的必须写
    8. virtual void BuyTicket() { cout << "买票-半价" << endl; }
    9. };

    目录

    一、认识多态

    1、多态的定义

    2、多态的构成条件

    二、虚函数的定义以及虚函数重写

    1、什么是虚函数

    2、虚函数重写的条件

    3、虚函数重写示例

    4、虚函数重写的两种特例情况

    (1) 协变

    (2) 析构函数的重写


    一、认识多态

    1、多态的定义

    多态指的是 父类和子类在执行相同行为的时候,出现了不同的结果。成人和学生执行买票这种行为的时候,成人的结果是全票,学生的结果是半票。

    实际上为了从语言的角度达到上述效果,其实就是父类Person 和子类Student 有着相同的成员函数 BuyTicket,父类去调用 BuyTicket 的结果是买全票,子类去调用 BuyTicket 的结果是买半票。我们的第一想法可能是这样

    1. Person p;
    2. p.BuyTicket(); // 成人买票
    3. Student s;
    4. s.BuyTicket(); // 儿童买票

    但是这样的灵活性不强,于是引入了多态的概念,仅仅使用一个对象,就可以达到两种效果。

    1. void Func(Person& p)
    2. {
    3. p.BuyTicket();
    4. }
    5. int main(){
    6. Person ps;
    7. Student st;
    8. Func(ps); // 传递Person对象买成人票
    9. Func(st); // 传递Student对象买半票
    10. }

    2、多态的构成条件

    在继承中要构成多态需要满足两个条件:

    • 必须通过基类的指针或者引用调用虚函数
    • 被调用的函数必须是虚函数,且派生类必须对基类的虚函数进行重写

    二、虚函数的定义以及虚函数重写

    1、什么是虚函数

    被 virtual 修饰的类成员函数称为 虚函数,这里的 virtual 跟之前虚继承里用到的 virtual 虽然是一个关键字,但是两者没有任何联系。

    2、虚函数重写的条件

    要重写虚函数需要满足一定的条件。既然是要让子类的某个函数来覆盖父类原本的函数,那就至少要求,子类的某个函数和父类的某个函数长得一模一样,这样才叫重写。

    虚函数重写条件:派生类有一个函数跟基类完全相同虚函数。(函数名、形参、返回值相同)

    3、虚函数重写示例

    大前提是两者有继承关系,然后是两个类有完全相同的虚函数(其实子类不加virtual也可)

    1. class Person {
    2. public:
    3. virtual void BuyTicket() { cout << "买票-全价" << endl; }
    4. };
    5. class Student : public Person {
    6. public:
    7. // 子类的 virtual 可以不写,但是父类的必须写
    8. virtual void BuyTicket() { cout << "买票-半价" << endl; }
    9. };

    4、虚函数重写的两种特例情况

    下面有两种特殊情况即便是不满足上述条件也构成虚函数重写

    (1) 协变

    协变指的是 基类和派生类的两个虚函数的返回值可以不同,但是返回值必须满足两个条件:

    • 返回值类型有继承关系
    • 返回值类型必须是指针 或者 引用
    1. class Person {
    2. public:
    3. virtual Person* BuyTicket() { cout << "买票-全价" << endl; }
    4. };
    5. class Student : public Person {
    6. public:
    7. virtual Student* BuyTicket() { cout << "买票-半价" << endl; }
    8. };

    (2) 析构函数的重写

    如果基类的析构函数为虚函数,无论是否加 virtual 关键字,都与基类的析构函数构成重写。

    1. class Person {
    2. public:
    3. virtual ~Person() { }
    4. };
    5. class Student : public Person {
    6. public:
    7. virtual ~Student() { } // 与派生类的析构函数构成重写(子类的 virtual 可以不写)
    8. };

    这是因为编译器对析构函数的名称进行了特殊处理,编译后析构函数的名称统一处理成 destructor

  • 相关阅读:
    【踩坑】工作中真实踩坑,一个or让sql变慢7倍
    前端-(3)
    C++ 并发编程 - 入门
    基于SSM的个人博客系统设计与实现(Java+MySQL)
    cesium 实现三维无人机航拍过程实景效果
    Spring Boot整合Spring Fox生成Swagger文档
    1.1 - Android启动概览
    YOLOv5算法改进(14)— 如何去更换主干网络(3)(包括代码+添加步骤+网络结构图)
    计算机网络基础 ARP协议 详详解----看完我的总结你就不用看别人的了!
    整合车辆出险报告Api接口,轻松管理车险理赔!
  • 原文地址:https://blog.csdn.net/challenglistic/article/details/127740672