I have a virtual base class, called AbstractHeap. AbstractHeap has a virtual function, "comp". It also has a (non-virtual) constructor and destructor that should be used by all derived classes, which are implemented.
AbstractHeap is inherited by MinHeap. It implements "comp". It also has a constructor, which just calls the base constructor.
Finally, Main.cpp just creates an instance of MinHeap.
When I compile the program, it gives me this error:
$ rm *.o && make
g++ -std=c++11 -c -g AbstractHeap.cpp
g++ -std=c++11 -c -g Main.cpp
g++ -std=c++11 -g -Wall Main.o AbstractHeap.o -o Main
Main.o: In function `MinHeap::MinHeap(int, int)':
/mnt/c/dev/Data_Structures/Lab7/MinHeap.h:8: undefined reference to `vtable for MinHeap'
/mnt/c/dev/Data_Structures/Lab7/MinHeap.h:8: undefined reference to `vtable for MinHeap'
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'Main' failed
make: *** [Main] Error 1
owen@MatrixSword:/mnt/c/dev/Data_Structures/Lab7$ rm *.o && make
g++ -std=c++11 -c -g AbstractHeap.cpp
g++ -std=c++11 -c -g Main.cpp
g++ -std=c++11 -g -Wall Main.o AbstractHeap.o -o Main
Main.o: In function `MinHeap::MinHeap(int, int)':
MinHeap.h:8: undefined reference to `vtable for MinHeap'
MinHeap.h:8: undefined reference to `vtable for MinHeap'
Main.o: In function `MinHeap::~MinHeap()':
MinHeap.h:5: undefined reference to `vtable for MinHeap'
MinHeap.h:5: undefined reference to `vtable for MinHeap'
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'Main' failed
make: *** [Main] Error 1
I've looked at this highly upvoted question, but it seems that the problem and solution involved QT, which I am not using.
Here's the code.
AbstractHeap.h
#ifndef ABSTRACT_HEAP_H
#define ABSTRACT_HEAP_H
#include <iostream>
#include <string>
using namespace std;
struct Item
{
int key = -1;
string data = "";
};
class AbstractHeap
{
private:
int k; //A k-heap.
int size;
Item* A; //The array.
public:
AbstractHeap(int k, int size);
~AbstractHeap();
//Comparison operator. Can be interpretted as c comp b. So, if you want a <, comp is a<b. If the result is true, a has a higher priority than b.
virtual bool comp(int a, int b) = 0;
};
#endif
AbstractHeap.cpp
#include "AbstractHeap.h"
#include <iostream>
#include <algorithm>
using namespace std;
AbstractHeap::AbstractHeap(int _k, int _size)
{
size = _size;
k = _k;
A = new Item[size];
}
AbstractHeap::~AbstractHeap()
{
delete [] A;
}
MinHeap.h
#ifndef MIN_HEAP_H
#define MIN_HEAP
#include "AbstractHeap.h"
class MinHeap : virtual public AbstractHeap
{
public:
MinHeap(int k, int size) : AbstractHeap{k, size} {};
bool comp(int a, int b);
};
#endif
MinHeap.cpp
#include "MinHeap.h"
bool MinHeap::comp(int a, int b)
{
return a < b;
}
Finally, here's my Makefile, in the unlikely event it is a result of poor Makefile writing.
Main: AbstractHeap.o Main.o
g++ -std=c++11 -g -Wall Main.o AbstractHeap.o -o Main
Main.o: Main.cpp
g++ -std=c++11 -c -g Main.cpp
AbstractHeap.o: AbstractHeap.cpp AbstractHeap.h MinHeap.cpp MinHeap.h
g++ -std=c++11 -c -g AbstractHeap.cpp
EDIT: The problem is fixed! The problem was actually three problems.
I removed "virtual" in the declaration of MinHeap. ("class MinHeap : public AbstractHeap")
I added "virtual" in front of the destructor in AbstractHeap. ("virtual ~AbstractHeap")
I added a compilation rule to create MinHeap.o, like so:
Main: AbstractHeap.o Main.o MinHeap.o
g++ -std=c++11 -g -Wall Main.o AbstractHeap.o MinHeap.o -o Main
Main.o: Main.cpp
g++ -std=c++11 -c -g Main.cpp
AbstractHeap.o: AbstractHeap.cpp AbstractHeap.h MinHeap.cpp MinHeap.h
g++ -std=c++11 -c -g MinHeap.cpp
g++ -std=c++11 -c -g AbstractHeap.cpp
Thanks everyone!
Two things:
1) This code is very unlikely to be what you want:
class MinHeap : virtual public AbstractHeap
virtual derivation is only of use when you are doing multiple inheritance (which you aren't here, from what you've shown), and even then it's best avoided.
You simply need:
class MinHeap : public AbstractHeap
I suspect this causes the error.
2) If you have a base class, its destructor should be declared as virtual, so:
virtual ~AbstractHeap();
If not, then when you delete a derived class object, the derived class destructor may be skipped. So you need a virtual destructor in the base class even if it does nothing and has an empty body, because the benefit is in the derived class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With