C++虚函数场景下两种成员函数调用方式的差异问询
C++虚函数场景下两种成员函数调用方式的差异问询
嘿,我来帮你拆解这两种调用方式的核心差异,结合你给出的代码(先补全你截断的main函数部分)来一步步说清楚~
首先先把完整可运行的代码贴出来:
#include <iostream> class A { public: virtual void main() { std::cout << "virtual void main of A" << std::endl; } int fun() { std::cout << "fun function: " << (long long)((void*)&A::main) << std::endl; // Member function pointer pointing to A::main auto ptr = &A::main; // Using 'this' pointer to call the function pointer (this->*ptr)(); // Explicitly calling A::main without virtual mechanism this->A::main(); return 0; } }; class B : public A { public: void main() override { std::cout << "virtual void main of B" << std::endl; } }; int main() { B* b = new B; A* a = b; std::cout << "=== Calling via B* ===" << std::endl; b->fun(); std::cout << "\n=== Calling via A* ===" << std::endl; a->fun(); delete b; return 0; }
接下来重点分析两种调用方式的区别:
1. (this->*ptr)():触发虚函数动态绑定
- 这里的
ptr是指向A::main的成员函数指针,但因为main是虚函数,这种调用方式会遵循动态绑定规则:它会根据this指针实际指向的对象类型,去对应类的虚函数表里查找并调用正确的函数版本。 - 比如当
this指向B对象时(不管是通过B*还是A*调用fun),这行代码都会输出virtual void main of B。 - 另外你打印的
&A::main的地址,其实对于虚函数来说,这个成员函数指针存储的并不是函数的真实内存地址,而是虚函数表中的偏移量(或者说索引信息),所以你看到的打印值是这个偏移相关的数值,而非函数实际地址。
2. this->A::main():强制静态绑定,绕过虚机制
- 这里用了显式的类作用域限定符
A::,这直接告诉编译器:不管当前对象是什么实际类型,都调用A类定义的main函数,完全绕过了虚函数的动态绑定机制。 - 所以不管
this指向的是A还是B对象,这行代码都会固定输出virtual void main of A,这个调用是在编译期就确定好的,属于静态绑定。
运行结果验证
上面补全的代码运行后会输出:
=== Calling via B* === fun function: [某个偏移数值] virtual void main of B virtual void main of A === Calling via A* === fun function: [同一个偏移数值] virtual void main of B virtual void main of A
你可以看到,两种指针调用fun时,(this->*ptr)()都调用了B的main,而this->A::main()始终调用A的版本,这就是两种调用方式的核心差异。
备注:内容来源于stack exchange,提问作者Diaos wang
相关产品推荐
相关产品推荐

