而不是使用虚拟函数,其中查找对象中的vtable指针,然后将其带到包含指向函数的指针的vtable,这样就不可能在对象中包含数据成员哪个直接指向函数?
答案 0 :(得分:1)
如果我理解你的问题,那么你正在寻找一种使用函数指针实现多态的方法。
嗯,它可能但是非常麻烦,容易出错,但是对于虚函数调用来说,编译器生成的de会超出de。
怎么做?
想法是使用函数指针。为了实现多态,它必须在基类中。
class B { // Base class
protected:
void (B::*fptest)(); // Function pointer to member function
public:
void mtest() // Class specific mebmer function
{ cout << "Base test\n"; }
void itest() // Polymorphic function
{ (this->*fptest)(); } // implemented by calling the poitner to member function
B() : fptest(&B::mtest) { } // Ctor must initialize the function pointer
virtual ~B() {}
};
class D : public B { // Derived class
public:
void mtest() // Class specific mebmer function
{ cout << "Derived test\n"; }
D() // Ctor
{ fptest = reinterpret_cast<void(B::*)()>(&D::mtest); } // not sure it's this safe in case of multiple inheritance !!
};
测试此构造的代码:
B b;
D d;
B *pb = &b, *pd = &d;
pb->itest();
pd->itest();
安全吗?
这有严重的局限性。例如:
它比vtable查找更高效吗?
否:查看为itest()
的每个多态调用执行的汇编程序:
; 41 : pd->itest(); // cod for the call for a derived object
mov ecx, DWORD PTR _pd$[ebp] ; load the oject address
call ?itest@B@@QAEXXZ ; call B::itest
; 16 : void itest() { (this->*fptest)(); }
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
mov DWORD PTR _this$[ebp], ecx ; use address of object as parameter
mov eax, DWORD PTR _this$[ebp] ; load the function pointer
mov ecx, DWORD PTR _this$[ebp] ; " "
mov edx, DWORD PTR [eax+4] ; call the function pointer
call edx
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
当然,优化器可以内联代码,删除一些推送和弹出,但一般原则是将生成间接代码。
vtable查找性能不够吗?
vtable查找基本上是从编译器计算的固定偏移量中加载函数指针。用于调用vitual test()函数的汇编程序代码如下所示:
39 : pd->test();
mov eax, DWORD PTR _pd$[ebp]
mov edx, DWORD PTR [eax]
mov ecx, DWORD PTR _pd$[ebp]
mov eax, DWORD PTR [edx]
call eax
结论
vtable查找至少与通过函数指针调用的性能相同。编译器负责所有初始化和最复杂的继承情况。更好地使用强大的虚拟函数,而不是尝试手动优于您的编译器。