了解链接器错误
Understanding linker errors
我用虚拟函数编写了以下程序:
struct A
{
virtual void foo() = 0;
A(){ init(); }
void init(){ foo(); }
};
struct B : A
{
virtual void foo(){ }
};
B a;
int main(){
return 0;
}
演示
我认为应该出现一些链接器错误,因为没有找到foo
的实现。我们得到了运行时错误。为什么?为什么不出现链接器错误?
这里首先要理解的是,在类A
的构造函数处于活动状态时对foo()
的调用会被调度到A::foo()
,即使正在构建的完整对象的类型为B
,而B
会覆盖foo()
。B::foo()
的存在被简单地忽略。
这意味着您的代码尝试调用A::foo()
。由于A::foo()
是一个纯虚拟函数,因此代码的行为是未定义的。
C++语言不能保证在这种情况下会发生什么样的"错误"。这意味着你对"链接器错误"的期望是完全没有根据的。如果程序尝试对纯虚拟函数执行虚拟调用,则行为只是未定义。从C++语言的角度来看,这是唯一可以说的。
这种未定义的行为将如何在实际实现中表现出来取决于实现。例如,允许未定义的行为通过编译时错误来表现自己。
在您的情况下,您的程序尝试对纯虚拟函数A::foo()
进行虚拟调用。在一般情况下,编译器通过实现多态性的运行时机制动态调度虚拟调用(所谓的虚拟方法表是最流行的)。在某些情况下,当编译器可以确定调用中使用的对象的确切类型时,它会优化代码,并对虚拟函数进行普通的直接(非动态)调用。
在实践中,如果一个函数是纯虚拟的,那么它的虚拟方法表条目包含一个空指针。对此类函数的动态调用通常会导致运行时错误。同时,对此类函数的直接(优化)调用通常会导致编译器或链接器错误。
在您的示例中,编译器没有优化调用。它通过虚拟方法表对A::foo()
进行了全面的动态调用。该表中的空指针触发了运行时错误。
如果您直接从构造函数调用纯虚拟函数
A() { foo(); }
典型的编译器通常会直接(优化)调用foo()
,这通常会导致链接器错误。
B
确实有foo
的实现,所以链接器没有问题。
据我所知,A
在错误的时间调用foo
这一事实并不需要编译器/链接器来解决。(尽管在这种情况下进行这样的检查可能很简单,但我相信我们可能会遇到更复杂的情况,这些情况可能更难或不可能被发现。)
您的错误是从构造函数中调用虚拟函数的结果。被调用的函数是A中的函数,而不是更多的派生函数。C++标准,第12.7.4节规定,
成员函数,包括虚拟函数(10.3),可以调用在建造或破坏期间(12.6.2)。当虚拟功能直接或间接从构造函数或从销毁器,包括在建造或销毁类非静态数据成员,以及调用的对象applies是正在构建或销毁的对象(称之为x),调用的函数是构造函数或中的最后一个重写器析构函数的类,而不是在更派生的类中重写它如果虚拟函数调用使用显式类成员访问(5.2.5),对象表达式是指x的完整对象或该对象的基类子对象之一,但不是x或其基类子对象,行为是未定义的。
现在,你在作弊。您正在从构造函数调用一个普通函数,然后从普通函数调用一个虚拟函数。将您的代码更改为,
struct A
{
virtual void foo() = 0;
A(){ foo(); }
};
你会得到你的错误,
warning: pure virtual ‘virtual void A::foo()’ called from constructor [enabled by default]
_ZN1AC2Ev[_ZN1AC5Ev]+0x1f): undefined reference to `A::foo()'
- Netbeans 10:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- CMake 错误:链接器命令失败,退出代码为 1 和 cpp.o 文件
- clang:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用) - 体系结构的未定义符号 x86_64:
- 如何修复 clang: 错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- Android NDK.Build命令失败.未定义的引用.clang++:错误:链接器命令失败,退出代码为1
- 使用cmake错误链接boost日志
- 错误:链接器命令失败,退出代码为 1(使用 -v 查看调用):在 Macbook 上
- C++ XCODE ld:找不到体系结构x86_64 clang 的符号:错误:链接器命令失败,退出代码为 1(使用 -
- clang:错误:链接器命令失败,C++代码中的退出代码为 1(使用 -v 查看调用)
- 静态库中的 g++ 错误链接函数
- 未定义的参考错误链接天然函数Android
- C++编译错误:ld:找不到体系结构x86_64 clang 的符号:错误:链接器命令失败,退出代码为 1(使用 -v
- QT Q_PROPERTY错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- ld:找不到体系结构x86_64 clang 的符号:错误:链接器命令失败,退出代码为 1(使用 -v 查看调用)
- OSX MOJAVE -LD:架构X86_64 clang找不到符号:错误:链接器命令失败,出口代码1
- C 错误链接器命令失败了出口代码1(使用-V查看调用)
- LD:架构x86_64 clang找不到符号:错误:链接器命令失败,出口代码1(使用-v to See
- 聚输出错误 - 链接列表
- Xcode链接器错误:链接器命令失败,退出代码为1(使用-v查看调用)
- 尝试构建C DLIB示例无法与数百个未定义的参考错误链接