0

Here is my code. First I defined two class:

#include <iostream>

using namespace std;

template<class Datatype>
class Node
{
    public:
        Node()
        {
            next = NULL;
            prev = NULL;
        }
        Node* getNext() const
        {
            return next;
        }
        Node* getPrev() const
        {
            return prev;
        }
        Datatype* getData() const
        {
            return &data;
        }
        void changeNext()
        {
            next = NULL;
        }
        void changeNext(Node& nextNode)
        {
            next = &nextNode;
        }
        void changePrev()
        {
            prev = NULL;
        }
        void changePrev(Node& prevNode)
        {
            prev = &prevNode;
        }
        Node* addNext(Node &);
        Node* addPrev(Node &);
        void nodeDel();
        void addData(Datatype &);
    private:
        Node* next;
        Node* prev;
        Datatype data;
};

template<class Datatype>
class Stack
{
    public:
        int push(Datatype &);
        Datatype pop();
        Datatype* peek();
    private:
        Node<Datatype> node;
};

This file is called my_node.h. The defines of some functions are in the other file, called my_node.cpp. It is like this:

#include "my_node.h"

using namespace std;

template <class Datatype>
Node<Datatype>* Node<Datatype>::addNext(Node<Datatype>& new_node)
{
    if (next == NULL)
    {
        changeNext(new_node);
        new_node.changePrev(*this);
    }
    else
    {
        Node* next = getNext();
        changeNext(new_node);
        new_node.changePrev(*this);
        next -> changePrev(new_node);
        new_node.changeNext(*next);
    }
    return &new_node;
}

template <class Datatype>
Node<Datatype>* Node<Datatype>::addPrev(Node<Datatype>& new_node)
{
    if (prev == NULL)
    {
        changePrev(new_node);
        new_node.changeNext(*this);
    }
    else
    {
        Node* prev = getPrev();
        changePrev(new_node);
        new_node.changeNext(*this);
        prev -> changeNext(new_node);
        new_node.changePrev(*prev);
    }
    return &new_node;
}

template<class Datatype>
void Node<Datatype>::nodeDel()
{
    if (prev == NULL && next == NULL)
        ;
    else if (prev == NULL)
    {
        Node* next = getNext();
        next -> changePrev();
    }
    else if (next == NULL)
    {
        Node* prev = getPrev();
        prev -> changeNext();
    }
    else
    {
        Node* next = getNext();
        Node* prev = getPrev();
        next -> changePrev(*prev);
        prev -> changeNext(*next);  
    }
    delete this;
    return;
}

template <class Datatype>
void Node<Datatype>::addData(Datatype &new_data)
{
    data = new_data;
}

template <class Datatype>
int Stack<Datatype>::push(Datatype &new_data)
{
    Node<Datatype> *pt_node = new Node<Datatype>;
    if (pt_node == NULL)
        return -1;

    Datatype *pt_data;

    pt_data = (this -> node).getData();
    pt_node -> addData(*pt_data);   
    (this -> node).addData(new_data);

    pt_node -> addNext(this -> node);
}

template <class Datatype>
Datatype Stack<Datatype>::pop()
{
    Datatype temp((this -> node).data);
    Datatype* new_fir = ((this -> node).getNext()) -> getData();
    (this -> node).addData(*new_fir);
    ((this -> node).getNext())->nodeDel();
    return temp;
}

template <class Datatype>
Datatype* Stack<Datatype>::peek()
{
    return (this->node).getData();
}

So above, I declare class in .h file and define some function of those classes in .cpp file. Now, I wrote a test file to test how it works. Test file test.cpp is like this:

#include <iostream>
#include "my_node.h"

using namespace std;

int main()
{
    Stack<float> test_stack;
    float a = 2.3;
    float b = 3.4;
    test_stack.push(a);
    test_stack.push(b);

    cout << test_stack.pop();
    cout << test_stack.pop();

    return 0;   
}

The command I use is simply:

g++ -g -Wall my_node.cpp test.cpp -o test

The compiling error is like this:

/tmp/ccYaX0on.o: In function `main':
/home/user/cpp/oop_eg/test.cpp:11: undefined reference to `Stack<float>::push(float&)'
/home/user/cpp/oop_eg/test.cpp:12: undefined reference to `Stack<float>::push(float&)'
/home/user/cpp/oop_eg/test.cpp:14: undefined reference to `Stack<float>::pop()'
/home/user/cpp/oop_eg/test.cpp:15: undefined reference to `Stack<float>::pop()'
collect2: ld returned 1 exit status

I feel so strange because I defined all those functions.

Thanks, Kevin Zhou

Shanpei Zhou
  • 371
  • 1
  • 2
  • 17

1 Answers1

2

With templates, you generally have to put the whole thing (declaration and definition) into a header file. That's because the code which uses the template needs to see the definition in order to instantiate it.

Basically, you can probably just cut+paste all the functions from my_node.cpp into my_node.h.

Peter Bloomfield
  • 5,578
  • 26
  • 37
  • Thank you so much. What if I only want to show others the interfaces I have which I declared in .h file? My idea is to define those functions in a .cpp file and I will compile it to a .o file then give to other. However, here if I want to make use of template, I cannot do this. – Shanpei Zhou Mar 03 '14 at 00:48
  • @user3352668 Unfortunately you can't hide template definitions in an object file. That's just a limitation of C++. The best you can do is add an abstraction layer which relies on pointer casting or polymorphism. That's messy though, and generally less efficient. – Peter Bloomfield Mar 03 '14 at 00:51
  • That's really a limitation. So you mean the containers in STL are all in .h files? – Shanpei Zhou Mar 03 '14 at 00:55
  • @user3352668 Yes. That means you can read all the code if you want. Some of it's a little obscure though! – Peter Bloomfield Mar 03 '14 at 01:03
  • @user3352668 (Strictly speaking, the files aren't actually called "*.h" -- the usually don't have any extension at all. They're treated as headers though.) – Peter Bloomfield Mar 03 '14 at 01:04