关于这个在 Linux 上使用 gcc 编译的程序中的 vtable,nm 告诉我什么?
What is nm telling me regarding the vtable in this program compiled with gcc on Linux?
我将一个基类更改为抽象(即我将其方法之一设为纯虚拟(并重新编译了它。当我去将它与派生类链接时,链接器抱怨 vtable。我用nm调查了事情,但我不确定nm到底在告诉我什么。我只是通过删除 *.o 文件并重新编译 Derived 类来解决问题,但我想了解这里的 vtable 到底发生了什么。
我最初的代码是这样的:
基数.h
class Base {
public:
virtual void doSomething();
};
基地.cpp
#include <iostream>
#include <Base.h>
void Base::doSomething() {
std::cout << "Base::doSomething()" << "n";
}
派生.h
#include <Base.h>
class Derived : public Base {
public:
Derived();
void doSomething() override;
};
派生.cpp
#include <iostream>
#include <Derived.h>
Derived::Derived() {
std::cout << "Derived::Derived() constructor" << "n";
}
void Derived::doSomething() {
std::cout << "Derived::doSomething()" << "n";
}
生成文件包含以下内容:
CXXFLAGS = -std=c++14 -pedantic -Wall -Werror -I ./
default: build
clean:
rm -f proggy
rm -f *.o
proggy: proggy.o Base.o Derived.o
g++ -o proggy proggy.o Base.o Derived.o
Base.o: Base.cpp Base.h
Derived.o: Derived.cpp Derived.h
然后我跑了,一切都很好。作为记录,我在这一点上也运行了nm,如下所示:
$ nm -C Derived.o | grep Base
00000000 W Base::Base()
00000000 W Base::Base()
00000000 n Base::Base()
U typeinfo for Base
U vtable for Base
我看到Base 的 typeinfo未定义,但这一切似乎对此都足够满意。
此外,在 Base.o 中,现阶段有这个:
nm -C Base.o | grep Base
000000d4 t _GLOBAL__sub_I__ZN4Base11doSomethingEv
00000000 T Base::doSomething()
00000044 R typeinfo for Base
0000004c R typeinfo name for Base
00000038 R vtable for Base
然后我更改了 Base.h 和 Base.cpp如下所示以使类抽象:
基数.h
class Base {
public:
virtual void doSomething() = 0; // pure virtual
};
基地.cpp
#include <iostream>
#include <Base.h>
// void Base::doSomething() {
// std::cout << "Base::doSomething()" << "n";
// }
然后当我运行 make 时,我收到此错误:
$ make proggy
g++ -std=c++14 -pedantic -Wall -Werror -I ./ -c -o Base.o Base.cpp
g++ -o proggy proggy.o Base.o Derived.o
Derived.o:(.rodata+0x5c): undefined reference to `typeinfo for Base'
Derived.o: In function `Base::Base()':
Derived.cpp:(.text._ZN4BaseC2Ev[_ZN4BaseC5Ev]+0x48): undefined reference to `vtable for Base'
collect2: error: ld returned 1 exit status
Makefile:17: recipe for target 'proggy' failed
make: *** [proggy] Error 1
其中 C++filt 告诉我以下内容:
$ c++filt _ZN4BaseC2Ev
Base::Base()
所以我然后按如下方式运行 nm,它告诉我:
$ nm -C Derived.o | grep Base
00000000 W Base::Base()
00000000 W Base::Base()
00000000 n Base::Base()
U typeinfo for Base
U vtable for Base
我可以看到Base 的 typeinfo是未定义的,但它也是在一开始,所以我认为这不是一个问题,但它确实如此。另请注意,现在在 Base.o 中没有提到 Base。
$ nm -C Base.o | grep Base
即此 nm 和 grep 命令未找到任何内容。
最后,我删除了所有 *.o 文件并再次运行 make,一切都很好。然后我运行 nm 查看 nm 报告的内容,它报告以下内容:
$ nm -C Derived.o | grep Base
00000000 W Base::Base()
00000000 W Base::Base()
00000000 n Base::Base()
00000000 V typeinfo for Base
00000000 V typeinfo name for Base
00000000 V vtable for Base
这一切意味着什么?
我的问题是:
- nm在这里告诉我什么以及之前出了什么问题 维表?
- 派生需要什么它没有?
- 为什么重新编译派生类可以解决问题,这做了什么 修复关于 vtable?
来自日志
$ make proggy
g++ -std=c++14 -pedantic -Wall -Werror -I ./ -c -o Base.o Base.cpp
g++ -o proggy proggy.o Base.o Derived.o
这意味着您的生成文件不会重新构建Derived.o
,而只会重新构建Base.o
。 这当然会导致问题。
您需要修复Makefile
以添加适当的依赖项,以便Derive.cpp
Base.h
。
vtable 存储已实现的虚拟方法的地址。如果一个类的所有方法都是纯虚拟的,并且没有一个被实现,那么现在还不需要生成 vtable*,因为没有办法单独实例化这样的类(在调试模式下,vtable 仍然可以生成,将所有内容指向陷阱函数(。
当你使用具有非纯虚函数的Base.h
编译Derived.cpp
时,它会引用Base
的 vtable。
当您随后将Base.h
更改为仅具有纯虚函数并重建Base.o
时,Base.o
的 vtable 将消失。此时您需要重建Derived.o
,否则它将继续引用不存在的 vtable。
当你重建Derived.o
时,编译器看到Base
是一个纯虚拟类,并在Derived.o
本身中为它生成一个vtable,因为它知道Base.o
中没有一个。
在基类中对虚函数重新排序后会出现另一个潜在问题。然后,派生类(如果不重新生成(最终可能会在其父类中调用错误的函数。
这就是为什么正确获取依赖项链以确保在必要时重新生成依赖对象文件很重要的原因。
Derived.o: Derived.cpp Derived.h Base.h
* 血腥的细节依赖于编译器,但 GCC 的做法是:由于不可能实例化纯虚拟类,因此 vtable 生成实际上被推迟到至少有一个实现,因为只有这样才有可能真正拥有该类的实例。因此,vtable是随每个派生的实现一起生成的,并导出为"弱"对象(类型V
(,以允许在链接时合并潜在的重复项。
- Mongodb c++驱动程序:如何查询元素的数组
- C++,系统无法执行指定的程序
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 重载操作程序时出错>>用于类中的字符串 memebr
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 试图在visual studio上用C++创建一个桌面应用程序
- 模板元程序查找相似的连续类型名称
- FFmpeg:制作一个应用程序比直接使用ffmepg更好吗
- 如何通过cpp程序运行shell脚本
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- IPC使用多个管道和分支进程来运行Python程序
- 如何将c++程序的一些输出传递给shell,以便在shell中使用
- 使用C++程序合并排序没有得到正确的输出
- 如何查看在程序级别为我的程序创建了多少 vtable 和 vpointer
- 关于这个在 Linux 上使用 gcc 编译的程序中的 vtable,nm 告诉我什么?
- 在 qt 控制台应用程序中未定义对 'vtable for myObj' 的引用 - 信号和插槽
- 简单的应用程序"undefined reference to vtable"错误?[Qt]
- 从 Objdump 实用程序检索 vptr(指向虚拟表又名 VTABLE 的指针)