3

I am trying to implement my own OrderedList data structure using class templates. Each constructor and function in my CPP file has an error on the opening '{'. The error reads "redefinition of FUNCTION_NAME FUNTION_NAME previously declared here".

I've had a few colleagues look at it, but to no avail. Here are my files and the error:

CPP FILE "MyOrderedList.cpp"

#include "MyOrderedList.h"

template <class E>
MyOrderedList<E>::MyOrderedList() {/*IMPLEMENTATION*/}

template <class E>
MyOrderedList<E>::MyOrderedList(const MyOrderedList<E>& orig) { /*IMPLEMENTATION*/}

template <class E>
void MyOrderedList<E>::operator =(const MyOrderedList<E>& orig){/*IMPLEMENTATION*/}

template <class E>
MyOrderedList<E>::~MyOrderedList() {/*IMPLEMENTATION*/}

template <class E>
void MyOrderedList<E>::insert(E data){/*IMPLEMENTATION*/}

template <class E>
E MyOrderedList<E>::get(int pos) const{/*IMPLEMENTATION*/}

template <class E>
Node<E>* MyOrderedList<E>::getHead() const{/*IMPLEMENTATION*/}

template <class E>
MyOrderedList<E> MyOrderedList<E>::kLargest(int k) const{/*IMPLEMENTATION*/}

template <class E>
MyOrderedList<E> MyOrderedList<E>::operator +(const MyOrderedList<E>& list {/*IMPLEMENTATION*/}

H FILE "MyOrderedList.h"

#ifndef MYORDEREDLIST_H
#define MYORDEREDLIST_H

#include <iostream>
#include <cstdlib>
#include "Node.h"

template <class E>
class MyOrderedList;
template <class E>
std::ostream& operator <<(std::ostream& out, const MyOrderedList<E>& list);

template <class E>
class MyOrderedList {
public:
    MyOrderedList();
    MyOrderedList(const MyOrderedList<E>& orig);
    void operator =(const MyOrderedList<E>& orig);
    virtual ~MyOrderedList();

    bool remove(E data);
    MyOrderedList<E> kLargest(int k) const;
    E get(int pos) const;
    void insert(E data);
    Node<E>* getHead() const;

    MyOrderedList<E> operator +(const MyOrderedList<E>& list);

    friend std::ostream& operator <<(std::ostream& out, const MyOrderedList<E>& list){/*IMPLEMENTATION*/}

private:
    Node<E>* head;
    int size;
};

#include "MyOrderedList.cpp"
#endif  //MYORDEREDLIST_H

Node.h

#ifndef NODE_H
#define NODE_H

#include <iostream>

template <class E>
class Node {
public:
    Node(const E& init_data = NULL, Node<E>* init_link = NULL){data = init_data; link = init_link;}
    Node(const Node<E>& orig);
    virtual ~Node();

    E getData() const{return data;}
    void setData(E newData);

    Node<E>* getLink(){return link;}
    void setLink(Node<E>* nextLink) {link = nextLink;}
private:
    E data;
    Node<E>* link;
};

#endif  /* NODE_H */

Compiler Errors

MyOrderedList.cpp:12: error: redefinition of `MyOrderedList<E>::MyOrderedList()'
MyOrderedList.cpp:12: error: `MyOrderedList<E>::MyOrderedList()' previously declared here
MyOrderedList.cpp:19: error: redefinition of `MyOrderedList<E>::MyOrderedList(const MyOrderedList<E>&)'
MyOrderedList.cpp:19: error: `MyOrderedList<E>::MyOrderedList(const MyOrderedList<E>&)' previously declared here
MyOrderedList.cpp:42: error: redefinition of `void MyOrderedList<E>::operator=(const MyOrderedList<E>&)'
MyOrderedList.cpp:42: error: `void MyOrderedList<E>::operator=(const MyOrderedList<E>&)' previously declared here
MyOrderedList.cpp:77: error: redefinition of `MyOrderedList<E>::~MyOrderedList()'
MyOrderedList.cpp:77: error: `virtual MyOrderedList<E>::~MyOrderedList()' previously declared here
MyOrderedList.cpp:91: error: redefinition of `void MyOrderedList<E>::insert(E)'
MyOrderedList.cpp:91: error: `void MyOrderedList<E>::insert(E)' previously declared here
MyOrderedList.cpp:119: error: redefinition of `E MyOrderedList<E>::get(int) const'
MyOrderedList.cpp:119: error: `E MyOrderedList<E>::get(int) const' previously declared here
MyOrderedList.cpp:134: error: redefinition of `Node<E>* MyOrderedList<E>::getHead() const'
MyOrderedList.cpp:134: error: `Node<E>* MyOrderedList<E>::getHead() const' previously declared here
MyOrderedList.cpp:140: error: redefinition of `MyOrderedList<E> MyOrderedList<E>::kLargest(int) const'
MyOrderedList.cpp:140: error: `MyOrderedList<E> MyOrderedList<E>::kLargest(int) const' previously declared here
MyOrderedList.cpp:158: error: redefinition of `MyOrderedList<E> MyOrderedList<E>::operator+(const MyOrderedList<E>&)'
MyOrderedList.cpp:158: error: `MyOrderedList<E> MyOrderedList<E>::operator+(const MyOrderedList<E>&)' previously declared here
user1334960
  • 55
  • 2
  • 7
  • 1
    See this question [Why should the implementation and the declaration of a template class be in the same header file](http://stackoverflow.com/questions/3749099/why-should-the-implementation-and-the-declaration-of-a-template-class-be-in-the) – Bo Persson Apr 15 '12 at 20:00

3 Answers3

4

Your problem is that you are including the definition of the functions in the header (indirectly through the #include "MyOrderedList.cpp". Because the functions are not declared as inline the compiler is generating the symbols in all translation units that include the header and thus you get multiply defined symbols.

One solution to the problem is declaring the functions as inline in the definition, so that the linker can discard the duplicates. Keeping the definitions in a separate file is not something new, but it is not too common either, some standard library implementations do that. But consider renaming the .cpp to something else to avoid confusion (most people will think that .cpp means that it is meant to be compiled, not included).

I would recommend, on the other hand, to simplify it a bit more, remove the .cpp altogether and just have the .h with everything (still mark all function definitions as inline) or even go one step further and define the functions inside the class definition, where they are inline by default.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • a little bit late... I keep splitting up my implementation details from header information when writing templates via putting implementation to `.ipp` files. All defined functions in `.ipp` need to be `inlined` to prevent multiple defined symbols. This works like a charm. Great Answer +1 – lifeOfPI Sep 02 '14 at 07:39
2

Your .cpp and .h files #include each other. Why?

geekosaur
  • 59,309
  • 11
  • 123
  • 114
  • I tried removing the "#include "MyOrderedList.cpp" from my .h file. I get a new error message: /cygdrive/c/Users/John/Desktop/Dropbox/Data Structures/Project7 Windows/MyOrderedList.h:(.rdata$_ZTV4NodeIiE[vtable for Node]+0x8): undefined reference to `Node::~Node()' /cygdrive/c/Users/John/Desktop/Dropbox/Data Structures/Project7 Windows/MyOrderedList.h:(.rdata$_ZTV4NodeIiE[vtable for Node]+0xc): undefined reference to `Node::~Node()' collect2: ld returned 1 exit status – user1334960 Apr 15 '12 at 19:52
  • Did you implement a body for `Node`'s destructor? – chris Apr 15 '12 at 19:55
  • Just pasted in my node.h file in my question. I have my default constructor: Node(const E& init_data = NULL, Node* init_link = NULL){data = init_data; link = init_link;} Node(const Node& orig); – user1334960 Apr 15 '12 at 20:01
0

The declarations and definitions for template classes need to stay together. There's nothing wrong with using #include on your .cpp file in order to do this, however your .cpp file will also need header guards (i.e. #ifndef MYORDEREDLIST_CPP etc). The usual approach however is simply to shove everything into the same .h file

Note - template classes/functions are the only time you should ever need to #include a .cpp file or put definitions into a header file.

Ben Cottrell
  • 5,741
  • 1
  • 27
  • 34
  • I do believe C++11 has extern templates :) – chris Apr 15 '12 at 20:00
  • Never #include a CPP file! Ever! For templates, stick the implementation inside the header file just below the class definition. – keelerjr12 Apr 15 '12 at 20:04
  • @keelerjr12 I think that's a matter of taste where templates are concerned - Marshal Cline's C++ FAQ also suggests it http://www.parashift.com/c++-faq-lite/templates.html#faq-35.13 – Ben Cottrell Apr 15 '12 at 20:11