Wil*_*ill 2 c++ inheritance gcc vtable nm
我将Base类更改为抽象(即我将其中一个方法设为纯虚拟)并重新编译它.当我将它与派生类链接时,链接器抱怨了vtable.我用nm调查了一些事情,但我不确定nm告诉我的是什么.我只是通过删除*.o文件并重新编译Derived类来解决问题,但我想了解这里的vtable究竟发生了什么.
我的原始代码是这样的:
Base.h
class Base {
public:
virtual void doSomething();
};
Run Code Online (Sandbox Code Playgroud)
Base.cpp
#include <iostream>
#include <Base.h>
void Base::doSomething() {
std::cout << "Base::doSomething()" << "\n";
}
Run Code Online (Sandbox Code Playgroud)
Derived.h
#include <Base.h>
class Derived : public Base {
public:
Derived();
void doSomething() override;
};
Run Code Online (Sandbox Code Playgroud)
Derived.cpp
#include <iostream>
#include <Derived.h>
Derived::Derived() {
std::cout << "Derived::Derived() constructor" << "\n";
}
void Derived::doSomething() {
std::cout << "Derived::doSomething()" << "\n";
}
Run Code Online (Sandbox Code Playgroud)
Makefile包含以下内容:
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
Run Code Online (Sandbox Code Playgroud)
然后我跑了make,一切都很顺利.为了记录,我在这一点上也运行了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
Run Code Online (Sandbox Code Playgroud)
我在哪里看到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
Run Code Online (Sandbox Code Playgroud)
然后,我按如下方式更改了Base.h和Base.cpp,以使类抽象:
Base.h
class Base {
public:
virtual void doSomething() = 0; // pure virtual
};
Run Code Online (Sandbox Code Playgroud)
Base.cpp
#include <iostream>
#include <Base.h>
// void Base::doSomething() {
// std::cout << "Base::doSomething()" << "\n";
// }
Run Code Online (Sandbox Code Playgroud)
然后当我运行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
Run Code Online (Sandbox Code Playgroud)
其中c ++ filt告诉我以下内容:
$ c++filt _ZN4BaseC2Ev
Base::Base()
Run Code Online (Sandbox Code Playgroud)
所以我接着运行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
Run Code Online (Sandbox Code Playgroud)
我可以看到Base的typeinfo是未定义的,但它也是一开始的,所以我认为这不是一个问题,但确实如此.另请注意,现在没有在Base.o中提及Base.
$ nm -C Base.o | grep Base
Run Code Online (Sandbox Code Playgroud)
即这个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
Run Code Online (Sandbox Code Playgroud)
这是什么意思呢?
我的问题是:
从日志
$ 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
Run Code Online (Sandbox Code Playgroud)
这意味着你的makefile不会重新构建Derived.o,只能重新构建Base.o.这当然会引起这个问题.
你需要修复的Makefile添加适当的依赖于Derive.cpp对Base.h.