C++ 虚函数 (virtual function) 介绍

news/2024/11/3 5:39:04/

文章目录

    • 1. 什么是虚函数
    • 2. 虚函数与非虚函数的区别
    • 3. 派生类中的虚函数
    • 4. 构造/析构函数可以是虚函数吗?
    • 5. 纯虚函数
      • 5.1 纯虚函数的定义
      • 5.1 纯虚函数的特定

1. 什么是虚函数

C++ 对象有三大特性:继承、封装、多态;虚函数就是实现多态的一种方式。

虚函数是指加了 virtual 修饰词的类的成员函数,但 virtual 关键字并非强制必须要有的。

对于某些函数,当基类希望派生类重新定义合适自己的版本时,基类就把这些函数声明为虚函数

以下是一个虚函数的简单定义:

class Animal {
public:virtual void makeSound() {std::cout << "Animal makes a sound" << std::endl;}
};

注意:virtual 关键字只能出现在类内部的函数声明中,不能用于类外部的函数定义。

2. 虚函数与非虚函数的区别

在 C++ 中,基类必须将它的两种成员函数区分开:

  • 基类希望直接继承给派生类而不需要改写的函数。静态绑定,即解析过程发生在编译而非运行时
  • 基类希望派生类进行覆盖的函数:定义为虚函数。动态绑定,即根据对象类型不同,调用该虚函数时可能执行基类的版本,也可能执行某个派生类的版本;因此需要在程序运行时确定。

3. 派生类中的虚函数

由于只有在程序运行时才知道调用哪个版本的虚函数,因此所有虚函数都必须有定义,就是不使用虚函数,也必须定义它。

基类定义的虚函数在所有派生类中都是虚函数

C++11 允许派生类使用 override 关键字显式地注明哪个成员函数是改写的基类的虚函数,代码示例如下:

class Animal {virtual void makeSound() {std::cout << "Animal makes a sound." << std::endl;}
};class Dog :public Animal {void makeSound() override {std::cout << "Dog makes a sound." << std::endl;}
};

完整代码示例如下:

#include <iostream>class Animal {
private:int nums;
public:Animal() = default;Animal(int nums_) : nums(nums_) {};virtual void printNum() {std::cout << "The number of animals is: " << nums << std::endl;}
};class Dog :public Animal {
private:int nums;
public:Dog() = default;Dog(int nums_) : nums(nums_) {};void printNum() override {std::cout << "The number of dog is: " << nums << std::endl;}
};int main(){Animal animal(100);animal.printNum();   // The number of animals is: 100Dog dog(5);dog.printNum();      // The number of dog is: 5return 0;
}

4. 构造/析构函数可以是虚函数吗?

答案:

构造函数不能是虚函数,析构函数可以是虚函数且最好设置为虚函数

(1)构造函数不可以是虚函数

构造函数是在创建对象时执行的,而虚函数是程序运行时执行的;也就是说在创建对象时虚函数还没确定用那个版本呢,所以构造函数不可以是虚函数。

(2)析构函数可以是虚函数且最好写成虚函数

如果析构函数不是虚函数,则容易造成内存泄露。原因为:

若有父类指针指向子类对象存在,需要析构的是子类对象;但父类析构函数不是虚函数,则只析构了父类,造成子类对象没有及时释放,引起内存泄漏。

5. 纯虚函数

5.1 纯虚函数的定义

虚函数与纯虚函数的区别如下:

  • 虚函数:子类可以(也可以不)重新定义基类的虚函数,在基类中定义为 virtual void func() {}
  • 纯虚函数:子类必须提供纯虚函数的个性化实现,在基类中定义为 virtual void func() = 0 {} 或 virtual void func() const = 0 {}

以下是一个纯虚函数的简单定义(声明):

class Animal {
public:virtual void makeSound() = 0 {}
};

5.1 纯虚函数的特定

(1)含有纯虚函数的类称为抽象类,抽象类不能被实例化。

与纯虚函数不同的是,包含虚函数的类可以被实例化。

如下面的代码中对 Animal 抽象类的实例化会编译报错。

#include <iostream>class Animal {// 这里的 = 0 没有任何实际意义,只起形式上的作用,告诉编译系统"这是纯虚函数"virtual void makeSound() = 0{}
};int main(){Animal animal();   // 报错:不能实例化抽象类return 0;
}

(2)纯虚函数只需要声明,不需要定义。

因为纯虚函数一定会被重新,所以在基类中声明即可,不需要定义。


http://www.ppmy.cn/news/641547.html

相关文章

VB6写nfc forum type 4 NDEF标签源码

NDEF 全称 NFC data exchange format 即 nfc 数据交换格式&#xff0c;是一种标准化的数据格式&#xff0c;可用于在任何兼容的NFC设备与另一个NFC设备或标签之间交换信息。数据格式由NDEF消息和NDEF记录组成。 本示例使用的发卡器&#xff1a;Android Linux RFID读写器NFC发卡…

让你的应用完美适配平板

/ 今日科技快讯 / 近日有博主曝光了一条奔驰方面发过来的短信&#xff0c;其中称他的车辆远程启动功能即将到期&#xff0c;而近期给出了400元的优惠&#xff0c;原本1298元三年的远程启动功能&#xff0c;现在仅需898元&#xff0c;一年期的只需498元。买车时就已经为远程…

华为eNSP配置GVRP

GVRP GVRP VLAN 注册协议是一种通用属性注册协议的应用&#xff0c;使得交换机之间能够相互交换VLAN配置信息&#xff0c;动态创建和管理VLAN。 GVRP三种注册模式 Normal模式&#xff1a;允许动态VLAN在端口上进行注册&#xff0c;同时会发送静态VLAN和动态VLAN的声明消息。…

web端的兼容性测试

Web的兼容性测试 Web兼容性测试类型主要有&#xff1a;操作系统&#xff0c;浏览器&#xff0c;分辨率和网速方面兼容性测试 兼容性测试是指待测试项目在特定的硬件平台上&#xff0c;不同的应用软件之间&#xff0c;不同的操作系统平台上&#xff0c;在不同的网络等环境中能正…

华为鸿蒙兼容性,华为鸿蒙自主操作系统曝光 兼容性很强

原标题&#xff1a;华为鸿蒙自主操作系统曝光 兼容性很强 华为鸿蒙自主操作系统曝光 兼容性很强 谷歌日前宣布暂停与华为相关业务&#xff0c;其中谷歌的 Android 系统也停止了对华为 GMS 的相关授权&#xff0c;此举对华为智能手机的影响还是蛮大的(海外市场)。 针对此事&…

华为新款台式机曝光!这外形、配置感受下

之前就有消息称&#xff0c;华为正在准备新的台式机&#xff0c;从现在的情况看确实如此。 根据爆料者_rogame 的消息&#xff0c;一款华为设备出现在了数据库中&#xff0c;而从一起曝光的图片看&#xff0c;华为新主机的外观设计比较简洁&#xff0c;机身正面有3个USB-A和一个…

移动端兼容性测试

可以关注来点儿干货呀公众号~ 什么是兼容性测试 兼容性测试是指测试软件在特定的硬件平台上、不同的应用软件之间、不同的操作系统平台上、不同的网络等环境中是否能够很友好的运行的测试。–【百度百科】 为什么要做兼容性测试 目前碎片化十分严重&#xff0c;尤其是安卓设备…

浏览器兼容和移动端适配方案

1.浏览器兼容&#xff1a; 一、css兼容: 不同浏览器的标签默认的margin和padding不同 问题症状&#xff1a; 随便写几个标签&#xff0c;不加样式控制的情况下&#xff0c;各自的margin 和padding差异较大。 碰到频率: 100% 解决方案&#xff1a; CSS里 *{margin:0;paddi…