Подтвердить что ты не робот

С++ undefined ссылка на vtable

Я изучаю С++. Я пытаюсь выполнить упражнение, когда я определяю несколько реализаций чистого виртуального класса с одной функцией. У меня возникли проблемы с привязкой класса, который использует эти реализации.

==> 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% уверен, что делаю по крайней мере одну глупость здесь, но мой мозг отказывается мне что-то сказать.

Я вижу этот вопрос, но мне не удалось исправить мою проблему.

4b9b3361

Ответ 1

Вы не включаете объектный файл Sum.o на свою линию компиляции и link (использование второго g++).

Ответ 2

Я столкнулся с одной и той же проблемой, но моя проблема заключалась в том, что я не записал код деструктора в мой .cpp файл.

class.h:

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

class.cpp:

MyClass::MyClass() {}

Он просто дал мне сообщение об ошибке vtable, и реализация (пустой) деструктора решила проблему.

[Edit] Таким образом, исправленный файл класса выглядит следующим образом:

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

Ответ 3

Несколько человек уже указали на решение проблемы, которую вы видели.

Я добавлю что-то другое. Вам нужны только защитники заголовков в ваших заголовках. Вы включили их в свои исходные файлы, где они действительно не имеют смысла. Например, я прокомментировал строки, которые вам действительно не нужны (или даже хотят) в 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() поэтому синтаксически они могут использоваться почти как функции).

Ответ 4

Эта ошибка также возникает, если вы забыли = 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 С++ не знает, что это чистая виртуальная функция, рассматривает его как объявление, ожидая более позднего определения.

Протестировано на g++ 5.2.1.

Ответ 5

Вы просто компилируете BasicMath.cpp без Sum.cpp - ваш компоновщик понятия не имеет о Sum.cpp. Вам нужно будет скомпилировать их оба вместе, т.е. Sum.cpp BasicMath.cpp за один раз, или вы можете самостоятельно скомпилировать файлы .cpp, а затем создать исполняемый файл, вызвав g++ с обоими файлами .o.

Ответ 6

Я обычно сталкиваюсь с этой ошибкой, когда я случайно забыл =0 в конце одной из моих функций в чистом виртуальном классе.

Ответ 7

Моя проблема была немного больше связана с Qt, но некоторые ответы дали мне хороший совет. Поэтому я проверил написание заголовочного файла, включенного в файл *.pro. Поскольку я добавил их сам, мне не хватало письма.