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


    多态指的是 父类和子类在执行相同行为的时候,出现了不同的结果。而虚函数是实现多态的重要条件之一。下面以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

  • 相关阅读:
    MySQL数据库期末考试试题及参考答案(03)
    进阶:Python序列的修改、散列和切片
    【c#】IEnumerable、IEnumerator、yield、Unity协程相关
    动态内存管理
    操作系统权限提升(二十五)之数据库提权-Centos7 安装MySQL
    vuex实现简易购物车加购效果
    计算机毕业设计ssm+vue基本微信小程序的拼车自助服务小程序
    接口注意事项---再次巩固,多看看不会亏!
    回归分析:多项式回归与广义线性回归,非线性问题的拟合
    Windows C++ 使用WinAPI实现RPC
  • 原文地址:https://blog.csdn.net/challenglistic/article/details/127740672