【问题标题】:c++ undefined reference to vtablec++ 未定义对 vtable 的引用
【发布时间】:2010-11-24 23:18:27
【问题描述】:

我正在学习 C++。我正在尝试做一个练习,我用一个函数定义一个纯虚拟类的几个实现。我在链接使用这些实现的类时遇到问题。

==> BasicMath.h <==
#ifndef BASIC_MATH_H
#define BASIC_MATH_H

#include<string>
#include<vector>    

class BasicMath { };


#endif // BASIC_MATH_H

==> Operation.h <==

#ifndef OPERATION
#define OPERATION

#include<string>
#include<vector>    

class Operation {
 public:
  virtual void perform(std::vector<std::string> vec) = 0;
};


#endif // OPERATION

==> Sum.h <==
#ifndef SUM_H
#define SUM_H

#include "Operation.h"

class Sum: public Operation {
 public:
  void perform(std::vector<std::string> vec);
};

#endif // SUM_H

==> BasicMath.cpp <==
#ifndef BASIC_MATH_C
#define BASIC_MATH_C

#include <string>
#include <vector>
#include <iostream>
#include "BasicMath.h"
#include "Sum.h"

int main(int argc, char* argv[]) {
  Sum op;
}

#endif // BASIC_MATH_C

==> Sum.cpp <==
#ifndef SUM_C
#define SUM_C

#include <vector>
#include <string>
#include <iostream>
#include "Sum.h"

void Sum::perform(std::vector<std::string> vec) {
    using namespace std;
    int total = 0;
    cout << "Total: " << total << "\n";
};

#endif // SUM_C

编译:

$ g++ -c Sum.cpp
$ g++ -o BasicMath BasicMath.cpp
/tmp/cc1VXjNl.o:BasicMath.cpp:(.text$_ZN3SumC1Ev[Sum::Sum()]+0x16): undefined reference to `vtable for Sum'
collect2: ld returned 1 exit status

我 95% 确定我在这里至少做了一件愚蠢的事情 - 但我的大脑拒绝告诉我是什么。

我看到了this 的问题,但未能解决我的问题。

【问题讨论】:

  • 旁注:您肯定希望通过引用而不是值传递 std::vector。
  • 旁注2:具有虚函数的类应该有一个虚析构函数。
  • 我已经添加了 g++ 标签,因为您的问题是如何让编译器(更准确地说是链接器)链接目标文件,这取决于编译器。

标签: c++ g++


【解决方案1】:

我刚遇到同样的问题,但我的问题是我的.cpp文件中没有写析构函数。

class.h:

class MyClass {
public:
    MyClass();
    virtual ~MyClass();
};

class.cpp:

MyClass::MyClass() {}

它只是给了我 vtable 错误消息,实现(空)析构函数解决了这个问题。

[编辑] 因此,更正后的类文件如下所示:

MyClass::MyClass() {}
MyClass::~MyClass() {}

【讨论】:

  • 显然,这很常见。 +1 ...这帮助我解决了同样的问题。
  • 第二个代码块不是你说的“实现(空)析构函数”,而是实现构造函数。
  • 第二个代码块故意显示产生错误的状态。我认为之后的句子足以解决问题,但我添加了“更正”的内容。
【解决方案2】:

您没有在编译和链接行中包含 Sum.o 目标文件(第二次使用 g++)。

【讨论】:

  • 好的,这非常容易。谢谢诺亚。采取其他关于通过参考等的观点。我将在接下来的工作中,现在我已经克服了这个错误。 g++手册进入阅读清单!
  • 正确,我没有编译包含类的cpp 文件。
【解决方案3】:

如果您忘记了纯虚函数的 = 0,也会发生该错误

错误:

class Base {
    public:
        virtual void f();
};

class Derived : public Base {
    public:
        virtual void f() {}
};

int main() {
    Derived d;
    Base *b = &d;
}

没有错误:

class Base {
    public:
        virtual void f() = 0;
};

这是因为没有= 0,C++不知道它是一个纯虚函数,把它当作一个声明,期待后面的定义。

g++ 5.2.1 上测试。

【讨论】:

  • 你救了我的命 XD
【解决方案4】:

已经有几个人指出了您所看到问题的解决方案。

我会添加一些完全不同的东西。你只需要在你的头文件中使用头文件。您也已将它们包含在您的源文件中,它们确实有意义。例如,我在 sum.cpp 中注释掉了你真正不需要(甚至不需要)的行:

//#ifndef SUM_C
//#define SUM_C
//
#include <vector>
#include <string>
#include <iostream>
#include "Sum.h"

void Sum::perform(std::vector<std::string> vec) {
    using namespace std;
    int total = 0;
    cout << "Total: " << total << "\n";
};

//#endif // SUM_C

只是 FWIW,而不是 perform,我会使用 operator()

class Operation {
 public:
  virtual void operator()(std::vector<std::string> vec) = 0;
};

并且(显然)这也是您为Sum 超载的内容。使用它,而不是类似的东西:

Sum op;
op.perform();

你会使用类似的东西:

Sum op;
op();

当你将你的类与调用函数之类的操作的其他类(例如标准库中的类)结合起来时,这特别方便,无论它们是真正的函数还是“仿函数”(像这样的类,重载operator()所以在语法上它们几乎可以像函数一样使用)。

【讨论】:

  • 嗨,Jerry - 我在查看了一些具有 cs.wustl.edu/~schmidt/ACE.html 样式的 ACE 代码后,在我的源代码中添加了守卫。也许这是某些框架所必需的,或者现在已经失效了?
【解决方案5】:

当我不小心忘记了纯虚拟类中一个函数末尾的=0 时,我通常会遇到此错误。

【讨论】:

  • 这与它无关。 =0 表示您的课程将是抽象的。我想问题是你忘了写一个函数体。
  • 谢谢,这个答案对我有帮助。
  • @EboMike 使用... = 0时不需要body。所以它会解决一些问题(虽然不是析构函数)。
【解决方案6】:

您只是在没有 Sum.cpp 的情况下编译 BasicMath.cpp - 您的链接器不知道 Sum.cpp。您需要将它们一起编译,即Sum.cpp BasicMath.cpp 一次性编译,或者您可以独立编译 .cpp 文件,然后通过调用 g++ 和两个 .o 文件来创建可执行文件。

【讨论】:

    【解决方案7】:

    我遇到了和你一样的问题,我通过在CMakeLists.txt中添加三行解决了这个问题,即:

    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    set(CMAKE_AUTOUIC ON)
    

    【讨论】:

    • 您好,请记住,正如 cmake 手册所示,这些都是针对 cmake 和 QT 项目的 ;-)
    猜你喜欢
    • 1970-01-01
    • 2014-06-04
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多