C++中通过虚表访问函数
Accessing functions through virtual tables in C++
我有两个类 B和D
class B{
public:
virtual int prva()=0;
virtual int druga(int)=0;
};
class D: public B{
public:
virtual int prva(){return 42;}
virtual int druga(int x){return prva()+x;}
};
我的任务是创建一个函数,它接受指向对象 B 的指针并打印 returning 方法 'prva' 和 'druga' 的值而不使用它们的名称(通过虚拟访问 table)
我写了下面的代码,它成功地打印了方法 'prva' 的 returning 值,但是对于第二种方法 'druga'
却没有做同样的事情
typedef int (*PTRFUN1)(void);
typedef int (*PTRFUN2)(int);
void function (B* var){
int* vptr = *(int**)var;
PTRFUN1 fun1 = (PTRFUN1)vptr[0];
PTRFUN2 fun2 = (PTRFUN2)vptr[1];
pprintf("Prva:%d\n", fun1());
printf("Druga:%d\n", fun2(2));
}
int main(void){
B *pb = new D();
function(pb);
}
这段代码执行打印:"Prva:42"
无法在 'druga' 中调用 prva()
,我不明白为什么。
此外,如果我简单地删除 prva()
的调用并让主体只是 return x
,方法 'druga' 将始终 return“42”或任何数字我让 'prva' return 无论我尝试通过 fun2()
发送什么参数
任何ides我在这里做错了什么,我应该如何访问方法?
无法在标准 C++ 中访问虚拟 table。事实上,该语言甚至没有虚拟 table 是什么的概念。 Virtual table 是实现动态调度的特定(且流行)方式。
Any ides what am I doing wrong here
当您通过 vptr
间接访问时,程序的行为未定义。
一些实现可能有办法在 C++ 中访问 table,但没有标准的方法。如果您的编译器没有,那么唯一的方法就是研究编译器如何实现它,编写程序以在汇编中访问它。
@eerorika 的回答是 100% 正确的,你不应该使用任何会导致未定义行为的东西。
但是,如果您仍然想走这条路,您可以通过将 B
指针作为第一个参数传递给 prva
& druga
.[=21 来修复您的代码=]
prva
和 druga
等成员函数有一个隐含的 this
参数,您需要将其传递给函数。
所以类似的东西:
typedef int (*PTRFUN1)(void* that);
typedef int (*PTRFUN2)(void* that, int);
void function (B* var){
void** vptr = *(void***)var;
PTRFUN1 fun1 = (PTRFUN1)vptr[0];
PTRFUN2 fun2 = (PTRFUN2)vptr[1];
printf("Prva:%d\n", fun1(var));
printf("Druga:%d\n", fun2(var, 2));
}
应该 工作(仍然依赖于编译器和 100% 未定义的行为)
Here's a Fiddle 给它。
编辑:
还有一种方法可以调用函数而不使用它们的名称,这不是未定义的行为。
您可以为此使用 Pointer to Member Functions:
typedef int (B::*PTRFUN1)();
typedef int (B::*PTRFUN2)(int x);
void function (B* var){
PTRFUN1 fun1 = &B::prva;
PTRFUN2 fun2 = &B::druga;
printf("Prva:%d\n", (var->*fun1)());
printf("Druga:%d\n", (var->*fun2)(2));
}
这样不会造成UB,仍然可以满足你不使用函数名调用的要求。
Here's a Fiddle 指向成员函数的变体。
我有两个类 B和D
class B{
public:
virtual int prva()=0;
virtual int druga(int)=0;
};
class D: public B{
public:
virtual int prva(){return 42;}
virtual int druga(int x){return prva()+x;}
};
我的任务是创建一个函数,它接受指向对象 B 的指针并打印 returning 方法 'prva' 和 'druga' 的值而不使用它们的名称(通过虚拟访问 table)
我写了下面的代码,它成功地打印了方法 'prva' 的 returning 值,但是对于第二种方法 'druga'
却没有做同样的事情typedef int (*PTRFUN1)(void);
typedef int (*PTRFUN2)(int);
void function (B* var){
int* vptr = *(int**)var;
PTRFUN1 fun1 = (PTRFUN1)vptr[0];
PTRFUN2 fun2 = (PTRFUN2)vptr[1];
pprintf("Prva:%d\n", fun1());
printf("Druga:%d\n", fun2(2));
}
int main(void){
B *pb = new D();
function(pb);
}
这段代码执行打印:"Prva:42"
无法在 'druga' 中调用 prva()
,我不明白为什么。
此外,如果我简单地删除 prva()
的调用并让主体只是 return x
,方法 'druga' 将始终 return“42”或任何数字我让 'prva' return 无论我尝试通过 fun2()
任何ides我在这里做错了什么,我应该如何访问方法?
无法在标准 C++ 中访问虚拟 table。事实上,该语言甚至没有虚拟 table 是什么的概念。 Virtual table 是实现动态调度的特定(且流行)方式。
Any ides what am I doing wrong here
当您通过 vptr
间接访问时,程序的行为未定义。
一些实现可能有办法在 C++ 中访问 table,但没有标准的方法。如果您的编译器没有,那么唯一的方法就是研究编译器如何实现它,编写程序以在汇编中访问它。
@eerorika 的回答是 100% 正确的,你不应该使用任何会导致未定义行为的东西。
但是,如果您仍然想走这条路,您可以通过将 B
指针作为第一个参数传递给 prva
& druga
.[=21 来修复您的代码=]
prva
和 druga
等成员函数有一个隐含的 this
参数,您需要将其传递给函数。
所以类似的东西:
typedef int (*PTRFUN1)(void* that);
typedef int (*PTRFUN2)(void* that, int);
void function (B* var){
void** vptr = *(void***)var;
PTRFUN1 fun1 = (PTRFUN1)vptr[0];
PTRFUN2 fun2 = (PTRFUN2)vptr[1];
printf("Prva:%d\n", fun1(var));
printf("Druga:%d\n", fun2(var, 2));
}
应该 工作(仍然依赖于编译器和 100% 未定义的行为)
Here's a Fiddle 给它。
编辑:
还有一种方法可以调用函数而不使用它们的名称,这不是未定义的行为。
您可以为此使用 Pointer to Member Functions:
typedef int (B::*PTRFUN1)();
typedef int (B::*PTRFUN2)(int x);
void function (B* var){
PTRFUN1 fun1 = &B::prva;
PTRFUN2 fun2 = &B::druga;
printf("Prva:%d\n", (var->*fun1)());
printf("Druga:%d\n", (var->*fun2)(2));
}
这样不会造成UB,仍然可以满足你不使用函数名调用的要求。
Here's a Fiddle 指向成员函数的变体。