C++ 函数虚表和虚表指针***

本文深入探讨了C++中的虚函数表(vtable)机制,通过具体的代码示例,详细解释了虚函数如何在运行时被调用,包括如何通过基类指针调用派生类的虚函数,以及如何直接通过虚函数表访问这些函数。
#include <iostream>

class Base 
{
public:
	Base() { std::cout << "Base()" << std::endl; }
	virtual ~Base() { std::cout << "~Base()" << std::endl; }
	virtual void
#ifdef _WIN32
		__cdecl
#endif
		fn(int i) { std::cout << "Base::echo(" << i << ")" << std::endl; }
};

class Derived : public Base {
public:
	Derived() : Base() { std::cout << "Derived()" << std::endl; }
	virtual ~Derived() { std::cout << "~Derived()" << std::endl; }
	virtual void
#ifdef _WIN32
		__cdecl
#endif
		fn(int i) { std::cout << "Derived::fn(" << i << ")" << std::endl; }
};
int main()
{

#if 1				
	typedef void(
#ifdef _WIN32
		__cdecl
#endif
		*TFunction)(void*, int);

	Derived d;
	Base* p = &d;

	// On many platforms, std::size_t is synonymous with std::uintptr_t.
	size_t* vptr = reinterpret_cast<size_t*>(p);
	size_t* vtable = reinterpret_cast<size_t*>(*vptr);

	//p->fn(2);			//Error	C2248 'Base::fn': cannot access private member declared in class 'Base'

// #ifdef _WIN32
// 	TFunction invoker = reinterpret_cast<TFunction>(vtable[1]);
// #else
// 	TFunction invoker = reinterpret_cast<TFunction>(vtable[2]);
// #endif
	
	TFunction invoker = reinterpret_cast<TFunction>(vtable[0]);		//destructor
	TFunction invoker1 = reinterpret_cast<TFunction>(vtable[1]);	//fn
	TFunction invoker2 = reinterpret_cast<TFunction>(vtable[2]);	//fn1

	invoker(p, 0);
	invoker1(p, 1);
	invoker2(p, 2);
#endif
	system("pause");
	return 0;


}
#pragma once

#include <iostream>

class Base 
{
public:
	Base() { std::cout << "Base()" << std::endl; }
	virtual ~Base() { std::cout << "~Base()" << std::endl; }

private:
	virtual void
#ifdef _WIN32
		__cdecl
#endif
		fn(int i) { std::cout << "Base::fn(" << i << ")" << std::endl; }
};

class Derived : public Base 
{
public:
	Derived() : Base() { std::cout << "Derived()" << std::endl; }
	virtual ~Derived() { std::cout << "~Derived()" << std::endl; }
// 	virtual void
// #ifdef _WIN32
// 		__cdecl
// #endif
// 		fn(int i) { std::cout << "Derived::fn(" << i << ")" << std::endl; }

private:
	virtual void
#ifdef _WIN32
		__cdecl
#endif
		fn(int i) { std::cout << "Derived::fn(" << i << ")" << std::endl; }

	virtual void
#ifdef _WIN32
		__cdecl
#endif
		fn1(int i) { std::cout << "Derived::fn1(" << i << ")" << std::endl; }
};


#if 0
#include <iostream>
using namespace std;

class Base
{
private:
	virtual void f0() { cout << "Base::f0()...." << endl; }
	virtual void f1() { cout << "Base::f1()...." << endl; }
	virtual void f2() { cout << "Base::f2()...." << endl; }
};

class Derive : public Base {};

typedef void(*Fun)(void);

int main(int argc, char* argv[])
{
	Derive d;
	Fun  pFun0 = (Fun)*((int*)*(int*)(&d) + 0);
	Fun  pFun1 = (Fun)*((int*)*(int*)(&d) + 1);
	Fun  pFun2 = (Fun)*((int*)*(int*)(&d) + 2);
	pFun0();
	pFun1();
	pFun2();

	return 0;
}

/*
Output:
Base::f0()....
Base::f1()....
Base::f2()....
*/

#endif

#if 0
#include <iostream>

using namespace std;

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

typedef void(*Fun)(void);

int main(void)
{
	Derived d;
	Fun pFun = NULL;
	for (int i = 0; i < 3; ++i)
	{
		pFun = (Fun)*((int *)*(int *)(&d) + i);
		pFun();
	}
	return 0;
}

/*VS2010环境下运行结果:
Derived::g
Base::f
Derived::h

结论:
1:  应该有假设“指向虚函数表vtable的虚函数表指针vt_ptr位于位于对象内存块的开始处”;
2 : (Fun)*((int *)*(int *)(&d) + i) : (将指针当做地址)
(&d) : 获得对象d的地址addr1,此地址对应整个对象d的内存块;
(int*)(&d) : 将Derived类型地址addr1强制转换为int类型地址addr2,此地址对应的内存块即为vt_ptr变量;
* (int*)(&d) : 取int类型地址addr2对应内存块中的值,得int类型值val1,该值其实为虚函数表的首地址;
(int*)*(int*)(&d) : 将int类型值val1强制转换为int类型地址addr3,该值即为虚函数表vtable的首地址;
((int*)*(int*)(&d) + i) : 对int类型地址addr3进行算术加,得到虚函数表中元素i的地址addr_i;
* ((int*)*(int*)(&d) + i) : 取int类型地址addr_i对应内存块中的值的int类型值val_i,该值其实为虚函数表中元素i中存储的对应的虚函数的指针;
(Fun)*((int *)*(int *)(&d) + i) : 将int类型值val_i强制转换为Fun类型地址(指针);

论证:
上述讨论中将指针看做地址,其实指针和地址应该是等效的:
int a = 0xAAAABBBB;
int *b = &a;
对以上两个定义语句,a和b都有自己的内存块,假设对应地址值分别为addr_a和addr_b。
则当执行表达式(int *)*b时,意思是将地址值addr_b对应内存块中存储的值(即为地址值addr_a)所对应的内存块中的值0xAAAABBBB强制转换为int*(即int类型指针,也即int类型地址)。
*/
#endif

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

隨意的風

如果你觉得有帮助,期待你的打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值