C++之虚函数
创始人
2024-03-28 08:15:41

都说面向对象的三大特性是封装、继承、多态。C++作为一门面向对象编程语言,肯定也是具备了面向对象的三大特性,那么在C++中是如何实现多态的呢?

在C++中是通过虚函数动态绑定的方式实现多态的。

虚函数与纯虚函数

首先我们来回顾一下虚函数,在C++中是使用virtual关键字修饰的函数就是虚函数,下面是一个简单的虚函数例子:

class Base{
public:// 虚函数,必须实现,否则编译报错virtual void f1() const{std::cout << "我是Base的f1函数" << std::endl;}
};class A:public Base{void f1() const override{std::cout << "我是A的f1函数" << std::endl;}
};

虚函数必须在基类中实现,如果不实现的话就会编译报错。

如果我们不想实现虚函数的话可以将其声明为纯虚函数,纯虚函数的声明方式如下:

virtual 返回值类型 函数名(函数参数) = 0;

声明了纯虚函数的类称为抽象类,继承抽象类的最终子类必须父类的纯虚函数,否则不能生产对应的类对象。以下是一个纯虚函数的例子:

class Base{
public:// 虚函数,必须实现,否则编译报错virtual void f1() const{std::cout << "我是Base的f1函数" << std::endl;}// 纯虚函数,不需要实现virtual void f2() const = 0;
};class A:public Base{
public:void f1() const override{std::cout << "我是A的f1函数" << std::endl;}void f2() const override{std::cout << "我是A的纯虚函数f2" << std::endl;}
};

有了虚函数我们就能通过基类的的指针进行动态绑定,在运行时访问到子类的函数,但是动态绑定只能发生在指针或引用上。例如在以下的例子中,函数test3是不会访问到子类的函数的, 它访问的函数依然是基类的虚函数,也就是说它没有发生动态绑定,因为它既不是指针也不是引用。

class Base{
public:// 虚函数,必须实现,否则编译报错virtual void f1() const{std::cout << "我是Base的f1函数" << std::endl;}
};class A:public Base{
public:void f1() const override{std::cout << "我是A的f1函数" << std::endl;}
};// 引用传递参数
void test1(const Base &base){base.f1();
}// 指针传递参数
void test2(Base *base){base->f1();
}// 非引用、非指针传递参数
void test3(Base base){base.f1();
}int main(int arg,char** argv) {Base *base =  new A();test1(*base);test2(base);test3(*base);return 0;
}

运行打印结果:

我是A的f1函数
我是A的f1函数
我是Base的f1函数

【学习地址】:FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发
【文章福利】:免费领取更多音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击1079654574加群领取哦~

  

如果一个类可能会被继承,这个类的析构函数应该被声明为一个虚函数,否则会引发内存泄漏。例如以下例子:

class Base{
public:// 虚函数,必须实现,否则编译报错virtual void f1() const{std::cout << "我是Base的f1函数" << std::endl;}~Base(){std::cout << "Base的析构函数" << std::endl;}
};class A:public Base{
public:void f1() const override{std::cout << "我是A的f1函数" << std::endl;}~A(){std::cout << "A的析构函数" << std::endl;}
};int main(int arg,char** argv) {Base *base =  new A();delete base;return 0;
}

运行输出如下:

Base的析构函数

从运行结果可以看出A没有被正确析构,这是因为它的基类Base的析构函数没有被声明为虚函数的原因,此时只要我们把Base类的析构函数声明为虚函数即可修复这个内存泄漏的问题,也就是:

class Base{
public:// 虚函数,必须实现,否则编译报错virtual void f1() const{std::cout << "我是Base的f1函数" << std::endl;}// 可能被继承的类的析构函数应该是一个虚函数virtual ~Base(){std::cout << "Base的析构函数" << std::endl;}
};

虚函数总结:

1、当我们在派生类中覆盖了某个虚函数时,可以再一次使用virtual关键字指出该函数的性质。然而这么做并非必须,因为一旦某个函数被声明成虚函数,则在所有派生类中它都是虚函数。
2、虚函数只有在引用或者指针调用时才会发生动态绑定;
3、基类的析构函数需要声明为虚函数;
4、虚函数必须要在基类实现,不实现,编译会报错;
5、如果子类没有实现父类的纯虚函数,则该子类不能被构造成一个对象。

多态实现原理-虚函数表

通过上面的例子我们知道了在C++中通过引用或指针的形式进行虚函数的动态绑定而实现多态,那么动态绑定在C++中是如何实现呢?答案是虚函数表。

所谓的虚函数表就是:

当编译器在编译过程中遇到virtual关键字时,它不会对函数调用进行绑定,而是为包含虚函数的类建立一张虚函数表Vtable。在虚函数表中,编译器按照虚函数的声明顺序依次保存虚函数地址。同时,编译器会在类中添加一个隐藏的虚函数指针VPTR,指向虚函数表。在创建对象时,将虚函数指针VPTR放置在对象的起始位置,为其分配空间,并调用构造函数将其初始化为虚函数表地址。需要注意的是,虚函数表不占用对象空间。

虚函数表总结:
1、单继承下的虚函数表

虚函数表中的指针顺序,按照虚函数声明的顺序排序;基类的虚函数指针在派生类的前面。

2、多继承下的虚函数表

多继承关系下会有多个虚函数表,也会有多个指向不同虚函数表的指针;

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...