指向成员函数的指针执行虚拟分派?
Pointer-to-member-function performs virtual dispatch?
我执行了以下代码。
#include <iostream>
class Base
{
public:
virtual void func()
{
std::cout<<"Base func called"<<std::endl;
}
};
class Derived: public Base
{
public:
virtual void func() override
{
std::cout<<"Derived func called"<<std::endl;
}
};
int main()
{
void (Base::*func_ptr)()=&Base::func; //Yes, the syntax is very beautiful.
Base* bptr=new Derived();
(bptr->*func_ptr)();
}
我的预期输出是Base func called
。然而,相反,输出是
Derived func called
这让我感到惊讶,因为我认为 func_ptr
应该只能看到 Base
成员(因为我认为 func_ptr
不会通过 [= 访问成员函数16=],但函数地址本身。
我想知道,在这种情况下虚拟调度是如何发生的(如何访问 虚拟 table),以及这种行为在哪里在 C++ 标准中定义(我找不到任何东西)?
参考[expr.call], specifically here
[If the selected function is virtual], its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call
无论是通过指针调用函数还是通过class成员访问都是一样的(ref);调用虚函数的实际函数最终取决于调用它的对象的实际类型。
[class.virtual] 下的标准中的一些(非规范性)注释说的大致相同:
[Note 3: The interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type)
[Note 4: [...] a virtual function call relies on a specific object for determining which function to invoke.
如果您想知道如何虚函数调度发生,您将需要寻找具体的实现,因为如何 未标准化。
(我真的很喜欢这篇文章 A basic glance at the virtual table,它展示了使用 C 实现它的一种可能方式)
- 你的理解有误。
- 这是一个实现细节。不同的编译器可能会以不同的方式实现它。如有疑问,look at the assembly。在这个特定的编译器中它实际上非常聪明。如果指向成员的指针中存储的值是偶数,则它是一个直接函数指针(所有函数都位于偶数地址)。如果是奇数,它是 vtable 中的偏移量加一。所有 vtable 偏移量也是偶数,因此要到达实际指针,它会减 1。
我执行了以下代码。
#include <iostream>
class Base
{
public:
virtual void func()
{
std::cout<<"Base func called"<<std::endl;
}
};
class Derived: public Base
{
public:
virtual void func() override
{
std::cout<<"Derived func called"<<std::endl;
}
};
int main()
{
void (Base::*func_ptr)()=&Base::func; //Yes, the syntax is very beautiful.
Base* bptr=new Derived();
(bptr->*func_ptr)();
}
我的预期输出是Base func called
。然而,相反,输出是
Derived func called
这让我感到惊讶,因为我认为 func_ptr
应该只能看到 Base
成员(因为我认为 func_ptr
不会通过 [= 访问成员函数16=],但函数地址本身。
我想知道,在这种情况下虚拟调度是如何发生的(如何访问 虚拟 table),以及这种行为在哪里在 C++ 标准中定义(我找不到任何东西)?
参考[expr.call], specifically here
[If the selected function is virtual], its final overrider in the dynamic type of the object expression is called; such a call is referred to as a virtual function call
无论是通过指针调用函数还是通过class成员访问都是一样的(ref);调用虚函数的实际函数最终取决于调用它的对象的实际类型。
[class.virtual] 下的标准中的一些(非规范性)注释说的大致相同:
[Note 3: The interpretation of the call of a virtual function depends on the type of the object for which it is called (the dynamic type)
[Note 4: [...] a virtual function call relies on a specific object for determining which function to invoke.
如果您想知道如何虚函数调度发生,您将需要寻找具体的实现,因为如何 未标准化。
(我真的很喜欢这篇文章 A basic glance at the virtual table,它展示了使用 C 实现它的一种可能方式)
- 你的理解有误。
- 这是一个实现细节。不同的编译器可能会以不同的方式实现它。如有疑问,look at the assembly。在这个特定的编译器中它实际上非常聪明。如果指向成员的指针中存储的值是偶数,则它是一个直接函数指针(所有函数都位于偶数地址)。如果是奇数,它是 vtable 中的偏移量加一。所有 vtable 偏移量也是偶数,因此要到达实际指针,它会减 1。