I'm relatively new to C++, and this is causing me a lot of headaches. I'm working on a student project about data structures, templates and inheritance. Let's talk about my problem.
I've got this file, container.hpp, that includes its .cpp on the bottom (cause this is supposed to be a template lib), containing all the base classes: Container--->LinearContainer, and Container--->TestableContainer--->SearchableContainer. Let's define this file:
container.hpp
#ifndef CONTAINER_HPP
#define CONTAINER_HPP
#include <functional>
namespace lasd {
/* ************************************************************************** */
class Container {
private:
protected:
unsigned long size = 0;
public:
// Destructor
virtual ~Container() = default;
// Copy assignment
Container& operator=(const Container&) = delete;
// Move assignment
Container& operator=(Container&&) noexcept = delete;
// Comparison operators
bool operator==(const Container&) const noexcept = delete;
bool operator!=(const Container&) const noexcept = delete;
// Specific member functions...
};
template <typename Data>
class LinearContainer : virtual public Container {
private:
protected:
public:
// Destructor
~LinearContainer() = default;
// Copy assignment
LinearContainer& operator=(const LinearContainer&) = delete;
// Move assignment
LinearContainer& operator=(const LinearContainer&&) noexcept = delete;
// Comparison operators
bool operator==(const LinearContainer&) const noexcept = delete;
bool operator!=(const LinearContainer&) const noexcept = delete;
// Specific member functions..
};
template <typename Data>
class TestableContainer : virtual public Container {
private:
protected:
public:
// Destructor
virtual ~TestableContainer() = default;
// Copy assignment
TestableContainer& operator=(const TestableContainer&) = delete;
// Move assignment
TestableContainer& operator=(TestableContainer&&) = delete;
// Comparison operators
bool operator==(const TestableContainer&) const noexcept = delete;
bool operator!=(const TestableContainer&) const noexcept = delete;
// Specific member functions...
};
template <typename Data>
class SearchableContainer : virtual public TestableContainer<Data> {
private:
protected:
public:
// Destructor
~SearchableContainer();
// Copy assignment
SearchableContainer& operator=(const SearchableContainer&) = delete;
// Move assignment
SearchableContainer& operator=(SearchableContainer&&) noexcept = delete;
// Comparison operators
bool operator==(const SearchableContainer&) const noexcept = delete;
bool operator!=(const SearchableContainer&) const noexcept = delete;
// Specific member functions...
};
/* ************************************************************************** */
#include "container.cpp"
}
#endif
I'm not going to post here the container.cpp cause we need more space for explain the main problem, and container.cpp contains two function implementations that are not related to our issue.
Now, it's time to talk about the effective child class: the vector, derived from LinearContainer and SearchableContainer.
vector.hpp
#ifndef VECTOR_HPP
#define VECTOR_HPP
/* ************************************************************************** */
#include "../container/container.hpp"
/* ************************************************************************** */
namespace lasd {
/* ************************************************************************** */
template <typename Data>
class Vector: public LinearContainer<Data>, public SearchableContainer<Data> {
private:
protected:
using LinearContainer<Data>::size;
Data* Elements = nullptr;
public:
// Default constructor
Vector() = default;
// Specific constructor
Vector(const unsigned long);
// Copy constructor
Vector(const Vector&);
// Move constructor
Vector(Vector&&) noexcept;
// Destructor
~Vector();
// Copy assignment
Vector& operator=(const Vector&);
// Move assignment
Vector& operator=(Vector&&) noexcept;
// Comparison operators
bool operator==(const Vector&) const noexcept;
inline bool operator!=(const Vector&) const noexcept;
// Specific member functions...
// Specific member functions (inherited from LinearContainer) ...
// Specific member functions (inherited from SearchableContainer)...
};
/* ************************************************************************** */
#include "vector.cpp"
}
#endif
And there's the function implementations, the .cpp file:
vector.cpp
#include <stdexcept>
// Specific constructor
template <typename Data>
Vector<Data>::Vector(const unsigned long newsize) {
Elements = new Data[newsize];
size = newsize;
}
// Copy constructor
template <typename Data>
Vector<Data>::Vector(const Vector<Data>& vec) {
Elements = new Data[vec.size];
size = vec.size;
for (unsigned long i = 0; i < size; i++) {
Elements[i] = vec.Elements[i];
}
}
// Move constructor
template <typename Data>
Vector<Data>::Vector(Vector<Data>&& vec) noexcept {
std::swap(Elements, vec.Elements);
std::swap(size, vec.size);
}
// Destructor
template <typename Data>
Vector<Data>::~Vector() {
delete[] Elements;
}
// Copy assignment
template <typename Data>
Vector<Data>& Vector<Data>::operator=(const Vector<Data>& vec) {
Vector<Data>* tmpvec = new Vector<Data>(vec);
std::swap(*tmpvec, *this);
delete tmpvec;
return *this;
}
// Move assignment
template <typename Data>
Vector<Data>& Vector<Data>::operator=(Vector<Data>&& vec) noexcept {
std::swap(Elements, vec.Elements);
std::swap(size, vec.size);
}
// Comparison operators
template <typename Data>
bool Vector<Data>::operator==(const Vector<Data>& vec) const noexcept {
if (size == vec.size) {
for (unsigned long i; i < size; i++) {
if (Elements[i] != vec.Elements[i]) {
return false;
}
}
return true;
}
else {
return false;
}
}
template <typename Data>
inline bool Vector<Data>::operator!=(const Vector<Data>& vec) const noexcept {
return !(*this == vec);
}
}
Then I've defined a simple main to test the vector creation and... BOOM! Weird errors appear on the terminal.
main.cpp
#include "vector/vector.hpp"
int main()
{
lasd::Vector<int> a(2);
return 0;
}
Errors showing in compiling phase:
/usr/bin/ld: /tmp/ccNaRUyt.o: in function `lasd::Vector<int>::~Vector()':
main.cpp:(.text._ZN4lasd6VectorIiED1Ev[_ZN4lasd6VectorIiED1Ev]+0x4f): undefined reference to `lasd::SearchableContainer<int>::~SearchableContainer()'
/usr/bin/ld: /tmp/ccNaRUyt.o: in function `virtual thunk to lasd::Vector<int>::~Vector()':
main.cpp:(.text._ZN4lasd6VectorIiED1Ev[_ZN4lasd6VectorIiED1Ev]+0xb6): undefined reference to `lasd::SearchableContainer<int>::~SearchableContainer()'
/usr/bin/ld: /tmp/ccNaRUyt.o: in function `virtual thunk to lasd::Vector<int>::~Vector()':
main.cpp:(.text._ZN4lasd6VectorIiED1Ev[_ZN4lasd6VectorIiED1Ev]+0x116): undefined reference to `lasd::SearchableContainer<int>::~SearchableContainer()'
/usr/bin/ld: /tmp/ccNaRUyt.o: in function `virtual thunk to lasd::Vector<int>::~Vector()':
main.cpp:(.text._ZN4lasd6VectorIiED0Ev[_ZN4lasd6VectorIiED0Ev]+0x56): undefined reference to `lasd::SearchableContainer<int>::~SearchableContainer()'
/usr/bin/ld: /tmp/ccNaRUyt.o: in function `virtual thunk to lasd::Vector<int>::~Vector()':
main.cpp:(.text._ZN4lasd6VectorIiED0Ev[_ZN4lasd6VectorIiED0Ev]+0xc6): undefined reference to `lasd::SearchableContainer<int>::~SearchableContainer()'
/usr/bin/ld: /tmp/ccNaRUyt.o:main.cpp:(.text._ZN4lasd6VectorIiED0Ev[_ZN4lasd6VectorIiED0Ev]+0x12f): more undefined references to `lasd::SearchableContainer<int>::~SearchableContainer()' follow
collect2: error: ld returned 1 exit status