首先写这篇文章之前,想要说明的是这篇文章告诉了我很多细节性的知识点,所以在此感谢该文的作者v_JULY_v,有读者想访问其主页可以点击这里
C++的虚函数大家比较熟悉,说到虚函数就必须提及多态性,C++的多态性能有效提高基类的可操作性,利用指向基类的指针或者基类的引用,根据运行时编译确定所需要执行的子类的方法,大大提高了代码的可重用性以及类的可扩展性与灵活性。这里多提一句:虚函数与多态性,涉及到的是父类与子类之间方法的重载,这里的重载可以理解为方法的覆盖,这与同一个类内部方法的重载是不一样的。那么有无虚函数到底有什么样的区别呢?我们先看一个例子:
一、一段代码告诉你虚函数的奇特
#include<iostream>
using namespace std;
class A
{
public:
virtual void fun{
cout<<"A"<<endl;
}
};
class B:public A
{
public:
virtual void fun{
cout<<"B"<<endl;
}
};
int main(int argc,char* argv)
{
A* a = new A();
A* b = new B();
a->fun();
b->fun();
}
请问输出的结果是什么?恩,答案是A和B。现在对上面的代码中A类和B类的fun函数去掉virtual关键字,执行同样的main函数,答案又是如何呢?这次的答案是A和A。
二、虚函数的本质
class Demo {
public:
virtual ~Demo();
virtual Demo& fun( float ) = 0;
float a() const { return _a; } //非虚函数,不作存储
virtual float b() const { return 0; }
virtual float c() const { return 0; }
// ...
protected:
Demo( float x = 0.0 );
float _a;
};
在这段代码里有5个函数,其中虚函数有4个,分别是虚析构函数(类在被定义为派生类的时候析构函数请定义为虚),fun(),a(),b(),c()。所以在该类产生的虚表中存放了这四个虚函数的地址,而由该类产生的对象则有两部分内容,第一个是成员变量_a,另一个则是指向虚函数表的指针vptr。当Demo类被继承时,子类一般会派生出属于自己的新成员函数与成员变量,这时候会发生什么呢?
我们假设在Demo类的基础上派生出新的成员变量float _b;当然了派生的时候可以重写虚方法,所以在派生类的对象中,新添加了新的部分_b,同时vptr指向了新的虚表。所以在一个类的生成过程中,会产生一定的内存分配来给虚表占用,这就会联想出一个问题:如果一个类反复的一层层继承下去,会不会导致大量的虚表产生而导致内存浪费呢?
请我们一起思考下吧...这也是MFC采用消息映射的原因之一。