欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > C++虚函数

C++虚函数

2025/2/25 9:47:36 来源:https://blog.csdn.net/weixin_45778713/article/details/144007985  浏览:    关键词:C++虚函数

在重读《C++ Primer Plus》第13章。这里总结一下读完后这一章学到的虚函数理解。

个人认为,虚函数是为了方便使用基类指针,管理多种不同类型的子类。

代码如下:

#include <iostream>
#include <vector>using namespace std;class fruit {public:virtual void variety() {cout << "水果" << endl;}
};class apple : public fruit {public:void variety() {cout << "苹果" << endl;}
};class banana : public fruit {
public:void variety() {cout << "香蕉" << endl;}
};int main()
{vector<fruit*> fruit_;apple fruit1;banana fruit2;fruit_.push_back(&fruit1);fruit_.push_back(&fruit2);for (auto it : fruit_){it->variety();}return 0;
}

运行结果如下

 

        上面这段代码,在容器中使用基类来管理派生类代码。根据对象初始化时派生类的类别,执行其对应的操作。这段代码中使用了虚函数标志。

该标志去掉后

#include <iostream>
#include <vector>using namespace std;class fruit {public:void variety() {cout << "水果" << endl;}
};class apple : public fruit {public:void variety() {cout << "苹果" << endl;}
};class banana : public fruit {
public:void variety() {cout << "香蕉" << endl;}
};int main()
{vector<fruit*> fruit_;apple fruit1;banana fruit2;fruit_.push_back(&fruit1);fruit_.push_back(&fruit2);for (auto it : fruit_){it->variety();}return 0;
}

运行结果如下图

 

        观察现象,可以得出,当基类函数前使用虚函数标识后,派生类重写该函数,根据派生类的不同,执行派生类中的代码段。

        书中关于这个现象p403有总结“如果没有使用关键字virtual,程序将根据引用类型或指针类型选择方法;如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择方法

        根据上面的现象已经可以很好的使用虚函数这个特性了,及想要使用基类指针或引用统一管理派生类对象,同时又需要使用派生类各自独特的实现。这时候就需要在基类中为这个公有方法使用虚函数virtual标志。

书中在后面又陈述了虚函数实现的本质,及虚函数表balaba~这里一并总结。

首先,静态联编和动态联编概念。

        p409“程序调用函数的时候将使用哪个可执行代码块呢?编译器负责回答这个问题。将源代码中的函数调用解释为执行特定的函数代码块被称为函数名联编。在C语言中,这非常简单,因为每个函数名都对应一个不同的函数。在C++中,由于函数重载的缘故,这项任务更复杂。编译器必须查看函数参数以及函数名才能确定使用哪个函数。然而,C++编译器可以在编译过程中完成这种联编。在编译过程中进行联编被称为静态联编,又称为早期联编。然而,虚函数使这项工作变得更困难。正如前面程序中示例那样,使用哪一个函数是不能在编译时确定的,因为编译器不知道用户将选择哪种类型的对象。所以,编译器必须生成能够在程序运行时选择正确的虚方法的代码,这被称为动态联编,又称为晚期联编。”

        动态联编要使程序能够在运行阶段进行决策,必须采取一些方法来跟踪基类指针或引用指向的对象类型,这增加了额外的处理开销。所以当非必须动态联编时应使用静态联编,即不使用virtual虚函数标志声明。

        “编译器处理虚函数的方法是:给每个对象添加一个隐藏成员。隐藏成员中保存了一个指向函数地址数组的指针。这种数组称为虚函数表。虚函数表中存储了为类对象进行声明的虚函数的地址。例如,基类对象包含一个指针,该指针指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针。如果派生类提供了虚函数的新定义,该虚函数表将保存新函数的地址;如果派生类没有重新定义虚函数,该vtbl将保存函数原始版本的地址。如果派生类定义了新的虚函数,则该函数的地址也将被添加到vtbl中。无论类中包含的虚函数是1个还是10个,都只需要在对象中添加1个地址成员,只是表的大小不同而已。

虚函数表如下图所示

类中使用虚函数后,会导致每个对象都将增大,增大量为存储地址的空间。

对于每个类,编译器都创建一个虚函数地址表(数组)

对于每个函数调用,都需要执行一项额外的操作,即到表中查找地址。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词