C++ 中虚函数指针的比较

Comparison of Virtual Function Pointers in C++

提问人:stett 提问时间:11/20/2015 最后编辑:curiousguystett 更新时间:12/7/2015 访问量:482

问:

假设我想检查一个子类是否实现了它的父级虚拟函数之一(别管这是否闻起来有糟糕的架构......这是一个练习)。如果我想查看两个常规函数是否相同,我可以检查一下。&f == &g

// Plain old functions
void f() {}
void g() {}

...

std::cout << "&f " << &f << "\n";               // "1"  OK, for some reason func ptrs are converted
std::cout << "&g " << &f << "\n";               // "1"  to booleans when printed. I can dig it.
std::cout << "&f == &g " << (&f == &g) << "\n"; // "0"  Good, &f and &g are unequal as expected.

但是对于虚拟成员函数,行为就不同了。

// Base class with a virtual
struct A {
    virtual void f() {}
};

// Subclass which implements f
struct B : public A {
    void f() {}
};

// Subclass which doesn't implement f
struct C : public A {};

...

std::cout << "&A::f " << &A::f << "\n"; // "1"
std::cout << "&B::f " << &B::f << "\n"; // "1"
std::cout << "&C::f " << &C::f << "\n"; // "1" ... okay ... annoying, but alright.

std::cout << "&A::f == &B::f " << (&A::f == &B::f) << "\n"; // "1" DANGER - why does &A::f == &B::f if &f != &g?
std::cout << "&A::f == &C::f " << (&A::f == &C::f) << "\n"; // "1"
std::cout << "&B::f == &C::f " << (&B::f == &C::f) << "\n"; // "1"

std::cout << "(void*)&A::f " << (void*)&A::f << "\n";   // "0x4084b0" Here's what I was actually looking for.
std::cout << "(void*)&B::f " << (void*)&B::f << "\n";   // "0x4084bc" Good - the B::f differs from A::f as it should
std::cout << "(void*)&C::f " << (void*)&C::f << "\n";   // "0x4084b0" Perfect.

std::cout << "(void*)&A::f == (void*)&B::f " << ((void*)&A::f == (void*)&B::f) << "\n"; // "0"
std::cout << "(void*)&A::f == (void*)&C::f " << ((void*)&A::f == (void*)&C::f) << "\n"; // "1"
std::cout << "(void*)&B::f == (void*)&C::f " << ((void*)&B::f == (void*)&C::f) << "\n"; // "0" These are the comparison results I want

所以我的问题在上面的代码中标记。为什么如果?有没有办法在不强制转换的情况下进行我想要的比较(由于 )会发出嘈杂的编译器警告?DANGER&A::f == &B::f&f != &gvoid*-Wpmf-conversions

C++ 比较 虚拟函数 成员指针

评论

0赞 Mats Petersson 11/20/2015
印刷品这一事实似乎有点奇怪。我很想知道被称为的过载函数是什么......另一个有趣的方面是,它甚至不会将你的强制转换编译为指针。&C::f1clang++
1赞 Mats Petersson 11/20/2015
我开始相信这是不可能的。从某种意义上说,指向虚函数的指针本身不是指向函数的指针,它是 vtable 的索引,因此无论实际类是什么,您都可以调用“正确”函数。
0赞 Mats Petersson 11/20/2015
如果你不介意那些非常未定义的代码,但由于 clang 不会编译代码,你发布的内容也是不可移植的,解决这个问题的一种方法是看一眼 vtable。[但是如果你有多个基类,它会变得很混乱]
0赞 stett 11/20/2015
@MatsPetersson,我有点想知道与您在第二条评论中提到的相同的事情。似乎强制转换为 (void*) 导致实际函数的地址从 vtable 中拉出,我希望这是标准的,但在文档中找不到它。我想这一定是 g++ 的东西,也是不可移植的位,但我会继续寻找。

答: 暂无答案