c++虚函数详解及其实现

虚函数:

虚函数是一种在基类定义为virtual的函数,并在一个或多个派生类中再定义的函数。虚函数的特点是,只要定义一个基类的指针,就可以指向派生类的对象。
注:无虚函数时,遵循以下规则:C++规定,定义为基类的指针,也能作指向派生类的指针使用,并可以用这个指向派生类对象的指针访问继承来的基类成员;但不能用它访问派生类的成员。
使用虚函数实现运行时的多态性的关键在于:必须通过基类指针访问这些函数。
一旦一个函数定义为虚函数,无论它传下去多少层,一直保持为虚函数。
把虚函数的再定义称为重写(overriding)而不叫重载(overloading)

纯虚函数:

是定义在基类中的一种只给出函数原型,而没有任何与该基类有关的定义的函数。纯虚函数使得任何派生类都必须定义自己的函数版本。否则编译报错
纯虚函数定义的一般形式:
Virtual type func_name(参数列表)=0;
含有纯虚函数的基类称为抽象基类。抽象基类又一个重要特性:抽象类不能建立对象。但是抽象基类可以有指向自己的指针,以支持运行时的多态性。

只要一个class声明了一个或者多个virtual function,编译器就会进行如下扩张操作
1.增加一个virtual function table(vtbl)。内含每一个有作用的virtual function的地址。每一个virtual function被指派一个表格索引值。
2.在每一个class object内放置一个指向virtual function table的指针vptr。

假设我们有这样的一个类:

	class Base { 
		public: 
		virtual void f() { cout << "Base::f" << endl; }
		virtual void g() { cout << "Base::g" << endl; }
		virtual void h() { cout << "Base::h" << endl; }
	};

在这里插入图片描述

一般继承(无虚函数覆盖)

下面,再让我们来看看继承时的虚函数表是什么样的。假设有如下所示的一个继承关系:
在这里插入图片描述
在这里插入图片描述
我们可以看到下面几点:
1)虚函数按照其声明顺序放于表中。
2)父类的虚函数在子类的虚函数前面。

一般继承(有虚函数覆盖)

覆盖父类的虚函数是很显然的事情,不然,虚函数就变得毫无意义。下面,我们来看一下,如果子类中有虚函数重载了父类的虚函数,会是一个什么样子?
在这里插入图片描述
在这里插入图片描述
我们从表中可以看到下面几点,
1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。
2)没有被覆盖的函数依旧。

多继承

在这里插入图片描述

不要在构造函数中调用虚函数

每一个含有virtual function的class都有一个虚函数表,每一个其class object含有一个指向该表的指针vptr。该表内依次存放指向类内的虚函数入口地址的指针。
编译器初始化vptr的时间:在base class constructors调用之后,但是在程序员提供的代码或是member initialization list中所列的member初始化操作之前。
在derived class中constructor的执行算法通常如下:
1.所有的base class的constructor会被调用。
2.对象的vptr会被初始化,并指向相关的virtual table
3.如果有member initialization list。将在constructor内扩展开来。
4.执行程序员提供的代码。

猜你喜欢

转载自blog.csdn.net/shayne000/article/details/88576268