单继承与多继承中的虚函数表和虚函数指针

首先,我们了解一下何为单继承,何为多继承??

单继承:一个子类只有一个直接父类。

多继承:一个子类有两个或多个直接父类。

单继承中的虚函数表分析:

示例程序:

#include <iostream>
using namespace std;

typedef void(*FUNC)();

class Base
{
public:
	virtual void func1()
	{
		cout << "Base::func1()" << endl;
	}
	virtual void func2()
	{
		cout << "Base::func2()" << endl;
	}
private:
	int _b;
};

class Derive :public Base
{
public:
	virtual void func1()
	{
		cout << "Derive::func1()" << endl;
	}
	virtual void func3()
	{
		cout << "Derive::func3()" << endl;
	}
	virtual void func4()
	{
		cout << "Derive::func4()" << endl;
	}
private:
	int _d;
};
void PrintVfptr(int* vptr)
	//打印虚函数表
{
	cout << "虚函数表: " << vptr << endl;
	for (int i = 0; vptr[i] != 0; ++i)
	{
		printf("第%d个虚函数:%p  >> ", i, vptr[i]);
		FUNC f = (FUNC)(vptr[i]);
		f();
	}
}

void Test()
{
	Base b;
	Derive d;

	int* vptrBase = (int*)(*(int*)(&b));
	int* vptrDeri = (int*)(*(int*)(&d));

	PrintVfptr(vptrBase);
	cout << endl;
	PrintVfptr(vptrDeri);

}

int main()
{
	Test();
	system("pause");
	return 0;
}

程序运行结果:

Base类(基类)的虚函数表:

Derive类(派生类)的虚函数表:

结论:

如果有虚函数表,那么只有一个虚函数表,并且按照虚函数声明的顺序顺序排列,派生类的虚函数紧接着基类的虚函数排列。

多继承中的虚函数表分析:

示例代码:

#include <iostream>
using namespace std;

typedef void(*FUNC)();
class Base
{
public:
	virtual void func1() = 0;
	virtual void func2() = 0;
};

class Base1:public Base
{
public:
	virtual void func1()
	{
		cout << "Base1::func1()" << endl;
	}
	virtual void func2()
	{
		cout << "Base1::func2()" << endl;
	}
private:
	int _b1;
};

class Base2: public Base
{
public:
	virtual void func1()
	{
		cout << "Base2::func1()" << endl;
	}
	virtual void func2()
	{
		cout << "Base2::func2()" << endl;
	}
private:
	int _b2;
};

class Derive : public Base1, public Base2
{
public:
	virtual void func1()
	{
		cout << "Derive::func1()" << endl;
	}
	virtual void func3()
	{
		cout << "Derive::func3()" << endl;
	}
	virtual void func4()
	{
		cout << "Derive::func4()" << endl;
	}
private:
	int _d;
};

void PrintVfptr(Base* b)
{
	int* vTable1 = (int*)(*(int*)b);
	cout << "虚函数表指针:" << vTable1 << endl;
	for (int i = 0; vTable1[i] != 0; ++i)
	{
		printf("第%d个虚函数指针: %p   >>", i, vTable1[i]);
		FUNC f = (FUNC)vTable1[i];
		f();
	}
	//int* vTable2 = (int*)(*((int*)b + sizeof(Base1) / 4));
	int* vTable2 = (int*)(*((int*)((char*)b + sizeof(Base1))));
	cout << "虚函数表指针:" << vTable2 << endl;
	for (int i = 0; vTable2[i] != 0; ++i)
	{
		printf("第%d个虚函数指针: %p   >>", i, vTable2[i]);
		FUNC f = (FUNC)vTable2[i];
		f();
	}
}

void Test()
{
	Base1 b1;
	Base2 b2;
	Derive d;
	PrintVfptr(&b1);
	cout << endl;
	PrintVfptr(&b2);
	cout << endl;
	PrintVfptr((Base1*)&d);
}

int main()
{
	Test();
	system("pause");
	return 0;
}

程序运行结果:

Base1的虚函数表:

Base2的虚函数表:

Derive的虚函数表:(有两个虚函数表)

多继承中的菱形继承:

示例代码:

#include <iostream>
using namespace std;

typedef void(*FUNC)();
class Base
{
public:
	virtual void func1()
	{
		cout << "Base::func1()" << endl;
	}
	virtual void func2()
	{
		cout << "Base::func2()" << endl;
	}
private:
	int _b;
};

class Parent1 :public Base
{
public:
	virtual void func1()
	{
		cout << "Parent1::func1()" << endl;
	}
	virtual void func3()
	{
		cout << "Parent1::func3()" << endl;
	}
	virtual void func4()
	{
		cout << "Parent1::func4()" << endl;
	}
	virtual void func5()
	{
		cout << "Parent1::func5()" << endl;
	}
private:
	int _p1;
};

class Parent2 :public Base
{
public:
	virtual void func1()
	{
		cout << "Parent2::func1()" << endl;
	}
	virtual void func3()
	{
		cout << "Parent2::func3()" << endl;
	}
	virtual void func6()
	{
		cout << "Parent2::func6()" << endl;
	}
	virtual void func7()
	{
		cout << "Parent2::func7()" << endl;
	}
private:
	int _p2;
};

class Child :public Parent1, public Parent2
{
public:
	virtual void func1()
	{
		cout << "Child::func1()" << endl;
	}
	virtual void func3()
	{
		cout << "Child::func3()" << endl;
	}
	virtual void func4()
	{
		cout << "Child::func4()" << endl;
	}
	virtual void func6()
	{
		cout << "Child::func6()" << endl;
	}
	virtual void func8()
	{
		cout << "Child::func8()" << endl;
	}
private:
	int _c;
};

void PrintVfptr(int* vptr)
	//打印虚函数表
{
	cout << "虚函数表: " << vptr << endl;
	for (int i = 0; vptr[i] != 0; ++i)
	{
		printf("第%d个虚函数:%p  >> ", i, vptr[i]);
		FUNC f = (FUNC)(vptr[i]);
		f();
	}
}
void Test()
{
	Base b;

	Parent1 p1; 
	Parent2 p2;

	Child c;

	int* vptr_B = (int*)(*(((int*)(&b))));

	int* vptr_P1 = (int*)(*(((int*)(&p1))));

	int* vptr_P2= (int*)(*(((int*)(&p2))));

	PrintVfptr(vptr_B);
	cout << endl;

	PrintVfptr(vptr_P1);
	cout << endl;

	PrintVfptr(vptr_P2);
	cout << endl;

	int* vptr_C_1 = (int*)(*(((int*)(&c))));
	int* vptr_C_2 = (int*)(*(int*)((char*)(&c) + sizeof(Parent1)));

	PrintVfptr(vptr_C_1);
	cout << endl;
	PrintVfptr(vptr_C_2);
	cout << endl;
}
int main()
{
	Test();
	system("pause");
	return 0;
}

运行结果:

其中,Child有两个虚函数表,因为它有两个直接父类。

总结:多继承中会有多个虚函数表,几重继承就会有几个虚函数表。这些虚函数表会按照派生的顺序依次排列。如果子类改写了父类的虚函数,那么就会用子类自己的虚函数覆盖相应的父类虚函数;如果子类有新的虚函数,那么就添加到第一个虚函数表的末尾。

时间: 2024-10-07 22:13:58

单继承与多继承中的虚函数表和虚函数指针的相关文章

解析虚函数表和虚继承

之前大二在学C++的时候一直对虚函数和虚继承有些晕(其实好像就是对virtual这个关键字不太熟悉)现在又学习到了一些,对虚函数表和虚继承的机制有了一点更深入的了解. 关于虚函数以及虚继承的基础知识,我自己也总结了一下,点击浅谈C++多态和C++继承可查看,在继承的总结的时候,我没有总结关于虚继承的知识,而且在多态总结也没有设计到太多的虚函数的知识,我是想把这两块集中在一起讲下,也算是自己对virtual关键字有个比较深入的了解吧.(本文所有代码均在VS2013编译器win32下测试) 另外对于

C++虚函数表与虚析构函数

1.静态联编和动态联编联编:将源代码中的函数调用解释为要执行函数代码. 静态联编:编译时能确定唯一函数.在C中,每个函数名都能确定唯一的函数代码.在C++中,因为有函数重载,编译器须根据函数名,参数才能确定唯一的函数代码. 动态联编:编译时不能确定调用的函数代码,运行时才能.C++中因为多态的存在,有时编译器不知道用户将选择哪种类型的对象,因此无法确定调用的唯一性,只有在运行时才能确定. 2.虚成员函数,指针或引用,动态联编指针或引用才能展现类的多态性.当类中的方法声明为virtual时,使用指

查看虚函数表

如果你看到这篇文章时,急着去吃饭或泡MM,请跳转到蓝色字段开始阅读. C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述.大家可以看看相关的C++的

C++多态篇3——虚函数表详解之多继承、虚函数表的打印

在上上一篇C++多态篇1一静态联编,动态联编.虚函数与虚函数表vtable中,我最后简单了剖析了一下虚函数表以及vptr. 而在上一篇文章C++多态篇2--虚函数表详解之从内存布局看函数重载,函数覆盖,函数隐藏中我详细介绍了虚函数的函数重载,函数覆盖以及函数隐藏的问题,其实在那一篇文章中,对单继承的虚函数已经做了十分详细的解答了,如果对前面有兴趣的人可以先看一下那篇文章. 在这一篇中,我会具体的分析一下在不同继承中(单继承,多继承)关于虚函数表在内存中的布局以及如何打印虚函数表.但是有关在虚继承

C++ 虚函数表解析 继承

C++ 虚函数表解析 陈皓 http://blog.csdn.net/haoel 前言 C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有"多种形态",这是一种泛型技术.所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法.比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议. 关于虚函数的使用方法,我在这里不做过多的阐述

菱形虚拟继承&虚函数表&对象模型

菱形继承: Assitant的菱形继承对象模型 Assitant中有两份Person成员,存在二义性和数据冗余. 所以我们引出了虚拟继承. virtual虚继.不会在子类中创建父类成员,但是子类中可以引用,就像指针一样.主要用在菱形继承,也叫钻石继承. 虚拟继承对象模型 class Student : vitrual public Person class Teacher : virtual public Peraon 虚函数表 通过一块连续内存来存储虚函数的地址.这张表解决了继承.虚函数(重写

C++中的虚函数表

学习了虚基类,立马就会想到虚函数,虚基类有个虚基类表与之对应,才使其发挥了不一般的作用,当然虚函数也有一个不函数表,其原理如下所示: 1.如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,那么即使加上了virtual关键字,也是不会进行滞后联编的. 2.只有类的成员函数才能说明为虚函数,因为虚函数仅适合用与有继承关系的类对象,所以普通函数不能说明为虚函数. 3.静态成员函数不能是虚函数,因为静态成员函数的特点是不受限制于某个对象. 4.内联(inline)函数不

C++中的虚函数以及虚函数表

一.虚函数的定义 被virtual关键字修饰的成员函数,目的是为了实现多态 ps: 关于多态[接口和实现分离,父类指针指向子类的实例,然后通过父类指针调用子类的成员函数,这样可以让父类指针拥有多种形态,所以称之为多态] 二.虚函数表 该表为一个类的虚函数的地址表,用于解决继承和覆盖的问题 1.拥有虚函数的类才有虚函数表 2.虚函数表属于类,然后类的所有对象通过虚函数表指针共享类的虚函数表 3.虚函数表的作用:当使用父类指针来操作子类对象时,虚函数表就像一个地图一样,指明了实际所应该调用的函数 4

深入C++对象模型&虚函数表

多态的实现机制: C++中虚函数的主要作用就是用来实现多态,就是使用基类的指针或者引用调用重写的虚函数,当父类的指针或引用指向父类对象时调用的是父类虚函数,当指向子类对象时调用的是子类的虚函数.那么这又是怎么实现的呢??? 这都是通过虚函数表实现的,虚函数表是通过一块连续内存来存储虚函数的地址.这张表解决了虚函数重写(地址进行覆盖)的问题 .在有虚函数的对象实例中都有一张虚函数表,虚函数表就像一张地图,指明了实际调用的虚函数函数. 例: class Base { public:        B