C++函数指针与虚函数指针对私有虚函数进行访问

C++函数指针与虚函数指针对私有虚函数进行访问


虚函数表与虚函数指针

(图片来自侯捷老师)
在这里插入图片描述

  • 虚函数表的首地址即为类对象的起始地址存放的指针,该指针即为虚函数表指针,指向虚函数表
  • 虚函数表中每一项都是一个指向虚函数地址的指针,非虚函数不在表中

函数指针

它其实就是一个特殊的指针,它用于指向函数被加载到的内存首地址,可用于实现函数调用。听上有点像函数名,函数名也是记录了函数在内存中的首地址,加()就可以调用。

函数指针就是一种特殊的指针。

如果你要声明一个变量:

int a ;

而一个指针呢:

int *a;

那一个函数指针,就是在一个变量指针的写法基础上加一个括号,告诉他这是一个指向函数的指针就可以:

int (*a)();

这样,a就是一个函数指针了。

这个括号(*a)一定要加,否则就成了int *a();编译器会认为这是一个 返回int *的函数a;

这时候呢,int (*a)();就声明了一个函数指针变量a,它可以指向一个返回int,参数列表为空的函数。

前面的int,就是这个函数指针的返回值,a是变量名,最后一个()是参数列表。

int function()  // 正确的函数声明
{
    return 0;
}
 
int (*a)()      // 错误:这是一个变量,不能当函数一样定义
{
    return 0;
}

//你只能这样:
int (*a)();     //声明一个函数指针变量a,
int main()
{
    a = function;   //给函数指针赋值。
    a();            //通过函数指针调用
    
    // 也可以直接把声明和赋值写在一起:这就像是 int i;和int * p = i;的区别
    int (*b)() = function;
    b();

    return 0;
}
//函数定义:
#include <iostream>
using namespace std;
typedef void (*f_ptr)();
void aaa()
{
    cout << "aaa" << endl ;
}

// void (* f())()
f_ptr f()   //返回值是函数指针的函数定义, 语义一目了然
{
    return aaa;
}

int main()
{
    // void (*(*f_ptr)())() = f;
    // f_ptr()(); 
    f_ptr (*ff)() = f; //返回函数指针的函数指针 
    ff()();
    return 0;
} 

通过虚函数表指针访问虚函数

int* vptr = (int*)*(int *)(&student);

上面这句意思是:

  1. 取对象地址&student
  2. 强转(int*)类型,此时是对象的第一个位置的值,也就是指向虚函数表指针的地址
  3. *(int *)(&student),对指针解引用,就是虚函数表指针
  4. (int* )* (int* )(&student),再次强转,此时指针指向表中第一个元素,该元素就是第一个类中的虚函数的地址
  5. 若要使用该虚函数,则再次强转为函数指针就可以直接使用
#include "pch.h"
#include <iostream>
using namespace std;
class Base {

public:

	virtual void f() { cout << "Base::f" << endl; }

	virtual void g() { cout << "Base::g" << endl; }

	virtual void h() { cout << "Base::h" << endl; }

};
int main()
{
	typedef void(*Fun)(void);

	Base b;

	Fun pFun = NULL;

	Base * p = &b;

	cout << "该对象的地址:" << p << endl;

	cout << "虚函数表的指针也是从这个地址"<< (int*)(&b) <<"开始存的" << endl << endl;

	cout << "虚函数表的指针指向的地址10进制:" << *(int*)(&b) << "即虚函数表的指针存的内容"<<endl;

	cout << "即虚函数表的地址:" << (int*)*(int*)(&b) << endl << endl;

	pFun = (Fun)*(int*)*(int*)(&b);//第一个虚函数的指针

	cout << "第一个虚函数的地址:" << pFun << endl;

	pFun();

	Fun gFun = NULL;
	gFun = (Fun)*((int*)*(int*)(&b) + 1);//第二个虚函数的指针

	Fun hFun = NULL;
	hFun = (Fun)*((int*)*(int*)(&b) + 2);//第三个虚函数的指针
}

输出结果:
在这里插入图片描述
另一个例子

#include<iostream>
#include<stdio.h>
using namespace std;

class A {
public:
	virtual void func1() {
		cout << "is A func1" << endl;
	}
	virtual void func2() {
		cout << "is A func2" << endl;
	}
};

class B: public A{
public:
	virtual void func1() {
		cout << "is B func1" << endl;
	}
	virtual void func2() {
		cout << "is B func2" << endl;
	}
};

typedef void (*Func)();
int main() {
	A* a = new B();
	Func f = nullptr;
	//f = (Func)*((int*)*(int*)(a));// is B func1
	f = (Func)*((int*)*(int*)(a)+1);// is B func2
	f();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

VioletEvergarden丶

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值