Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/154.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
指向虚拟成员函数的指针。它是如何工作的? 考虑下面的C++代码: class A { public: virtual void f()=0; }; int main() { void (A::*f)()=&A::f; }_C++_Virtual_Member Function Pointers - Fatal编程技术网

指向虚拟成员函数的指针。它是如何工作的? 考虑下面的C++代码: class A { public: virtual void f()=0; }; int main() { void (A::*f)()=&A::f; }

指向虚拟成员函数的指针。它是如何工作的? 考虑下面的C++代码: class A { public: virtual void f()=0; }; int main() { void (A::*f)()=&A::f; },c++,virtual,member-function-pointers,C++,Virtual,Member Function Pointers,如果我不得不猜测的话,我会说&A::f在本文中的意思是“A的f()实现的地址”,因为指向常规成员函数和虚拟成员函数的指针之间没有明确的分隔。由于A没有实现f(),这将是一个编译错误。然而,事实并非如此 不仅如此。以下代码: void (A::*f)()=&A::f; A *a=new B; // B is a subclass of A, which implements f() (a->*f)(); 将实际调用B::f 它是如何发生的?关于成员函数指针的信

如果我不得不猜测的话,我会说&A::f在本文中的意思是“A的f()实现的地址”,因为指向常规成员函数和虚拟成员函数的指针之间没有明确的分隔。由于A没有实现f(),这将是一个编译错误。然而,事实并非如此

不仅如此。以下代码:

void (A::*f)()=&A::f;
A *a=new B;            // B is a subclass of A, which implements f()
(a->*f)();
将实际调用B::f


它是如何发生的?

关于成员函数指针的信息太多了。在“行为良好的编译器”下有一些关于虚拟函数的东西,虽然Irc当我读到文章时我略去了这部分,因为文章实际上是关于在C++中实现委托。p>


简单的回答是,这取决于编译器,但有一种可能性是,成员函数指针被实现为一个结构,其中包含一个指向发出虚拟调用的“thunk”函数的指针。

它可以工作,因为标准规定应该这样做。我用GCC做了一些测试,结果表明,对于虚拟函数,GCC以字节为单位存储所讨论函数的虚拟表偏移量

struct A { virtual void f() { } virtual void g() { } }; 
int main() { 
  union insp { 
    void (A::*pf)();
    ptrdiff_t pd[2]; 
  }; 
  insp p[] = { { &A::f }, { &A::g } }; 
  std::cout << p[0].pd[0] << " "
            << p[1].pd[0] << std::endl;
}
struct A{virtual void f(){}virtual void g(){};
int main(){
工会督察
无效(A::*pf)();
ptrdiff_t pd[2];
}; 
insp p[]={{&A::f},{&A::g};

std::cout我不完全确定,但我认为这只是常规的多态行为。我认为
&A::f
实际上意味着类的vtable中函数指针的地址,这就是为什么没有得到编译器错误的原因。vtable中的空间仍然被分配,这就是您实际返回的位置


这是有意义的,因为派生类基本上用指向其函数的指针覆盖这些值。这就是为什么
(a->*f)(
在第二个示例中起作用-
f
引用了在派生类中实现的vtable。

嗨,你刚才提到了thunk。有什么好文章解释thunk吗?thunk一词指的是一段低级代码,通常由机器生成,用于实现特定软件系统的某些细节。"这个页面讨论了几种类型的Tunk,虽然不是这个特定的。我想我的问题的答案不是C++标准化的。但是VTABLE也是如此,但是我不知道任何编译器都不使用VTABLE作为虚拟函数的机制,所以我想也有一个标准的机制。only让我更加困惑。如果编译器在指向A的成员函数的指针中存储1和5,它如何判断这是vtable索引还是实地址?(请注意,指向常规成员函数和虚拟成员函数的指针之间没有区别)为什么这个答案会让你更加困惑?只要问清楚是否有什么不清楚的地方。这类事情不是标准化的。这取决于实现如何解决它。他们可以决定它是否是函数指针:我认为这就是为什么他们加1的原因。因此,如果数字没有对齐,它是一个可变的偏移量。如果对齐,它是可变的一个指向成员函数的指针。不过,这只是我的猜测。谢谢,这听起来很合乎逻辑。但是,C++实现有些效率。检查VC上的代码,结果完全不同。输出是“C01380C01390”,它看起来像是一个地址。请检查由@ OnByOne链接的快速委托文章。t包含关于其他编译器的好信息。我的答案当然是特定于GCC的。标准说这必须起作用。因此,符合标准的编译器将使它起作用。在除GCC之外的其他实现中,虚拟函数指针可以是16字节。如果指向常规membe的指针之间存在分隔,则可能会出现这种情况r函数和指向虚拟成员函数的指针。但是,正如我所提到的,没有,这就是它的全部内容。编译器绝对可以将所有方法(无论是否为虚拟方法)放在vtable中。如果它这样做,那么它就可以使用vtable索引来指向成员函数的指针。实际上,对于编译器来说,这非常简单-只需确保非虚拟重写器获得自己的vtable项,而不是重写基类项。因为编译器使其发生!如果调用普通方法与调用虚拟方法没有什么不同,为什么您认为在使用方法指针时代码会有任何不同。您认为编译器在翻译普通方法是什么(虚拟和ordingary)调用?