不同类的虚拟函数共享相同的(无效?)内存地址

Virtual Functions of different classes share same (invalid?) memory address

本文关键字:无效 内存 地址 虚拟 同类 函数 共享      更新时间:2023-10-16

请考虑以下代码片段:

#include<cstdio>
#include<iostream>
using namespace std;
class Class1{
public:
virtual void print(){
cout << "Class1"<<endl;
printf("%pn", &Class1::print);
}
};
class Class2{
public:
virtual void print(){
cout << "Class2"<<endl;
printf("%pn", &Class2::print);
}
};
class Class3{
public:
virtual void print(){
cout << "Class3"<<endl;
printf("%pn", &Class3::print);
}
};
int main(){
Class1 c1;
Class2 c2;
Class3 c3;
c1.print();
c2.print();
c3.print();
}

我在g++(MinGW) 8.2.0上编译了以下代码,并在cmd和Powershell上运行输出。(我不确定这是否重要。 我预计打印的三个地址是不同的。但是,打印的三个地址是相同的,在我的例子中是"00000001",这似乎也很奇怪,因为这听起来不像一个有效的地址(不是 4 的倍数)

  • 仅当使用关键字"虚拟"时,才会发生这种情况。
  • 类 2 是否继承自类 1 没有任何区别。(与 2-3、1-3 等相同)

据我所知,虚拟函数是用一种叫做"vtable"的东西实现的。我知道每个类都有一个指向表的秘密指针。但即使是这样,每个函数的地址不应该是不同的,或者至少是合法的吗?

我确实研究了其他问题,例如:这个,其中函数fork()是问题的中心;这个......在看了所有关于"相同地址"的问题之后,我想,也许这与操作系统有关?但在此之后,我找不到任何相关的东西。


TL;博士:

1.上面的代码打印三个相同的地址。为什么?这怎么可能?

2. 打印的地址看起来无效(00000001)。这是为什么呢?

您的代码具有未定义的行为。&Class3::print是指向成员函数的指针,但%p需要void *。 如果将指针投射到void *则获得有效结果。

#include<cstdio>
#include<iostream>
using namespace std;
class Class1{
public:
virtual void print(){
cout << "Class1"<<endl;
printf("%pn", (void*)&Class1::print);
}
};
class Class2{
public:
virtual void print(){
cout << "Class2"<<endl;
printf("%pn", (void*)&Class2::print);
}
};
class Class3{
public:
virtual void print(){
cout << "Class3"<<endl;
printf("%pn", (void*)&Class3::print);
}
};
int main(){
Class1 c1;
Class2 c2;
Class3 c3;
c1.print();
c2.print();
c3.print();
}

输出

Class1
0x400b50
Class2
0x400be0
Class3
0x400c70