Split single file into header and source fioles

Write your question here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  #include<iostream>
#include<fstream>
#include<string>

using namespace std;

template <class T>
class Node
{
private:
    T data;
    Node<T> *prev;
    Node<T> *next;
public:
    Node();
    Node(T data);
    T getData();
    void setData(T data);
    Node<T> *getPrev();
    void setPrev(Node<T> *prev);
    Node<T> *getNext();
    void setNext(Node<T> *next);
};

template <class T>
Node<T>::Node()
{
    prev = nullptr;
    next = nullptr;
}

template <class T>
Node<T>::Node(T data)
{
    this->data = data;
    prev = nullptr;
    next = nullptr;
}

template <class T>
T Node<T>::getData()
{
    return data;
}

template <class T>
void Node<T>::setData(T data)
{
    this->data = data;
}

template <class T>
Node<T> *Node<T>::getPrev()
{
    return prev;
}

template <class T>
void Node<T>::setPrev(Node<T> *prev)
{
    this->prev = prev;
}

template <class T>
Node<T> *Node<T>::getNext()
{
    return next;
}

template <class T>
void Node<T>::setNext(Node<T> *next)
{
    this->next = next;
}


template <class T>
class LinkedList
{
    Node<T> *head;
public:
    LinkedList();
    Node<T> *getHead();
    void setHead(Node<T> *head);
    bool isEmpty();
    Node<T> *searchNode(T k);
    void print();
    void insertNode(T k);
    void deleteNode(T k);
    ~LinkedList();
};

template <class T>
LinkedList<T>::LinkedList()
{
    head = nullptr;
}

template <class T>
LinkedList<T>::~LinkedList()
{
    while(!isEmpty())
        deleteNode(getHead()->getData());
}

template <class T>
Node<T> * LinkedList<T>::getHead()
{
    return head;
}

template <class T>
void LinkedList<T>::setHead(Node<T> *head)
{
    this->head = head;
}

template <class T>
bool LinkedList<T>::isEmpty()
{
    return getHead() == nullptr;
}

template <class T>
Node<T> *LinkedList<T>::searchNode(T k)
{
    Node<T> *p = getHead();
    while(p != nullptr && p->getData() != k)
        p = p->getNext();
    return p;
}

template <class T>
void LinkedList<T>::print()
{
    Node<T> * x = getHead();
    Node<T> * y = nullptr;

    cout<<"Przegladanie listy od glowy "<<endl;
    while(x != nullptr)
    {
        y = x;
        cout<<x->getData()<<" ";
        x = x->getNext();
    }
    cout<<"NULL"<<endl;
    cout<<endl;

    cout<<"Przegladanie listy od ogona "<<endl;
    while(y != nullptr)
    {
        cout<<y->getData()<<" ";
        y = y->getPrev();

    }
    cout<<"NULL"<<endl;
    cout<<endl;
}

template <class T>
void LinkedList<T>::insertNode(T k)
{
    Node<T> *x = new Node<T>(k);
    Node<T> *y = getHead();
    Node<T> *z = nullptr;
    while(y != nullptr && x->getData() > y->getData())
    {
        z = y;
        y = y->getNext();
    }
    x->setNext(y);
    if(y != nullptr)
            y->setPrev(x);
    if(z == nullptr)
    {
        setHead(x);
    }
    else
    {
        z->setNext(x);
    }
    x->setPrev(z);
}

template <class T>
void LinkedList<T>::deleteNode(T k)
{
    Node<T> *x = searchNode(k);

    if(x != nullptr)
    {
        if(x->getPrev() != nullptr)
            x->getPrev()->setNext(x->getNext());
        else
            setHead(x->getNext());
        if(x->getNext() != nullptr)
            x->getNext()->setPrev(x->getPrev());
        delete x;
    }
}

int main()
{
    fstream A,B;
    string pathA,pathB,lineA;
    LinkedList<string> L;
    cout<<"Enter the path to the file you want to read "<<endl;
    getline(cin,pathA);
    cout<<"Enter the path to the file you want to write "<<endl;
    getline(cin,pathB);
    A.open(pathA,ios::in);
    if(!A.good())
        return 1;
    while(getline(A,lineA))
    {
        L.insertNode(lineA);
    }
    A.close();
    B.open(pathB,ios::out);
    while(!L.isEmpty())
    {
        B<<L.getHead()->getData()<<endl;
        L.deleteNode(L.getHead()->getData());
    }
    B.close();
    return 0;
}


How can I split this code into

Node.h and Node.cpp
LinkedList.h and LinkedList.cpp
main.cpp

After division i would like to put it in Code::Blocks project






The declarations belong to the header files, and the implementations to the cpp files.

So lines 7 till 23 go to Node.h , lines 25 till 74 to Node.cpp, line 77 till 91 to LInkedList.h, 93 till 200 to LinkedList.cpp, and the remainder to main.cpp.

LinkedList.h and Node.cpp must include Node.h, LinkedList.cpp and main.cpp need including LinkedList.h.

A rule of Thumb is that you need include all the header files which provide the declarations of these types which you want using in your cpp (or h) file.
Last edited on
@nuderobmonkey

Except that templates pretty much have to go in the header file.
Neither Node nor LinkedList can have .cpp file because they are template.
With template classes, the compiler has to have access to the entire definition of the template at the point where the class is instantiated. It's not enough to simply proved the method declarations in the header and rely on the linker to sort it out, as with normal classes; you need to have the entire definition available to the compiler.

In practise, this means that you want the entire definition of the class, including the full method definitions, in the header file.

This is one of the reasons I hate templates...
Three files:
main.cpp
LinkedList.hpp
node.hpp

Compiled with:
g++ main.cpp

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>
#include<fstream>
#include<string>
#include "LinkedList.hpp"

using namespace std;

int main()
{
   fstream A, B;
   string pathA, pathB, lineA;
   LinkedList<string> L;

   cout << "Enter the path to the file you want to read\n";
   getline(cin,pathA);
   cout << "Enter the path to the file you want to write\n";
   getline( cin, pathB );

   A.open( pathA, ios::in );
   if ( !A.good() ) return 1;

   while( getline( A, lineA ) )
   {
      L.insertNode(lineA);
   }
   A.close();

   B.open( pathB, ios::out );
   while( !L.isEmpty() )
   {
       B << L.getHead()->getData() << '\n';
       L.deleteNode( L.getHead()->getData() );
   }
   B.close();
}




LinkedList.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#include <iostream>
#include "node.hpp"
using std::cout;
using std::endl;

template <class T>
class LinkedList
{
    Node<T> *head;
public:
    LinkedList();
    Node<T> *getHead();
    void setHead(Node<T> *head);
    bool isEmpty();
    Node<T> *searchNode(T k);
    void print();
    void insertNode(T k);
    void deleteNode(T k);
    ~LinkedList();
};

template <class T>
LinkedList<T>::LinkedList()
{
    head = nullptr;
}

template <class T>
LinkedList<T>::~LinkedList()
{
    while(!isEmpty())
        deleteNode(getHead()->getData());
}

template <class T>
Node<T> * LinkedList<T>::getHead()
{
    return head;
}

template <class T>
void LinkedList<T>::setHead(Node<T> *head)
{
    this->head = head;
}

template <class T>
bool LinkedList<T>::isEmpty()
{
    return getHead() == nullptr;
}

template <class T>
Node<T> *LinkedList<T>::searchNode(T k)
{
    Node<T> *p = getHead();
    while(p != nullptr && p->getData() != k)
        p = p->getNext();
    return p;
}

template <class T>
void LinkedList<T>::print()
{
    Node<T> * x = getHead();
    Node<T> * y = nullptr;

    cout<<"Przegladanie listy od glowy "<<endl;
    while(x != nullptr)
    {
        y = x;
        cout<<x->getData()<<" ";
        x = x->getNext();
    }
    cout<<"NULL"<<endl;
    cout<<endl;

    cout<<"Przegladanie listy od ogona "<<endl;
    while(y != nullptr)
    {
        cout<<y->getData()<<" ";
        y = y->getPrev();

    }
    cout<<"NULL"<<endl;
    cout<<endl;
}

template <class T>
void LinkedList<T>::insertNode(T k)
{
    Node<T> *x = new Node<T>(k);
    Node<T> *y = getHead();
    Node<T> *z = nullptr;
    while(y != nullptr && x->getData() > y->getData())
    {
        z = y;
        y = y->getNext();
    }
    x->setNext(y);
    if(y != nullptr)
            y->setPrev(x);
    if(z == nullptr)
    {
        setHead(x);
    }
    else
    {
        z->setNext(x);
    }
    x->setPrev(z);
}

template <class T>
void LinkedList<T>::deleteNode(T k)
{
    Node<T> *x = searchNode(k);

    if(x != nullptr)
    {
        if(x->getPrev() != nullptr)
            x->getPrev()->setNext(x->getNext());
        else
            setHead(x->getNext());
        if(x->getNext() != nullptr)
            x->getNext()->setPrev(x->getPrev());
        delete x;
    }
}



node.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
template <class T>
class Node
{
private:
    T data;
    Node<T> *prev;
    Node<T> *next;
public:
    Node();
    Node(T data);
    T getData();
    void setData(T data);
    Node<T> *getPrev();
    void setPrev(Node<T> *prev);
    Node<T> *getNext();
    void setNext(Node<T> *next);
};

template <class T>
Node<T>::Node()
{
    prev = nullptr;
    next = nullptr;
}

template <class T>
Node<T>::Node(T data)
{
    this->data = data;
    prev = nullptr;
    next = nullptr;
}

template <class T>
T Node<T>::getData()
{
    return data;
}

template <class T>
void Node<T>::setData(T data)
{
    this->data = data;
}

template <class T>
Node<T> *Node<T>::getPrev()
{
    return prev;
}

template <class T>
void Node<T>::setPrev(Node<T> *prev)
{
    this->prev = prev;
}

template <class T>
Node<T> *Node<T>::getNext()
{
    return next;
}

template <class T>
void Node<T>::setNext(Node<T> *next)
{
    this->next = next;
}
Hello nowy20180820,

Everyone above has very good points that will work. Although as lastchance says it worked in G++, but not everyone has G++ for a compiler.

As i have recently read here what you can do is say put the class "Node" in its ".hpp" file and put the member functions in a ".cpp" type file, but give it the extension ".imp" then at the bottom of the class after the closing } put #include "Node.imp" and you will have the same thing as previously mentioned.

I understand the concept here, but have not had the opportunity to test it yet. I think I will try it with your program.

Hope that helps,

Andy
Although as lastchance says it worked in G++, but not everyone has G++ for a compiler.

That's a strange comment. What about lastchance's solution do you think is specific to g++? What about lastchance's solution do you think might fail on other compilers?

@MikeyBoy,

That's a strange comment.
Sometimes I do strange things.

What about lastchance's solution do you think is specific to g++?
Maybe. It does not work in my VS2017 or when I used VS2015.

What about lastchance's solution do you think might fail on other compilers?
Possibly. It did fail in my VS2017.

In the end I based the statement on what I have read here Although kind of a generic synopsis of a concept.

Andy
What about lastchance's solution do you think is specific to g++?
Maybe. It does not work in my VS2017 or when I used VS2015.


I'm surprised. You can also compile it from the command line as
cl.exe main.cpp
(cl.exe being the C++ compiler associated with Visual Studio).

The only point that I was trying to make is that, whatever compiler is used, it is only directed at the main.cpp file, as that will "pull in" the headers as necessary.

I never use IDEs, so I have no idea if your header files were in the right place to be found. What exactly happened when you tried to compile main.cpp within Visual Studio?
Last edited on
@Handy Andy

As always, "it does not work" or "it did fail" are not useful problem statements. Tell us the error messages you got were, and maybe we can help solve the problem.

There is nothing in lastchance's solution that is dependent on a particular compiler. In fact, he's fundamentally done the same thing that you suggested in your own solution.
Last edited on
When i create new class in Code::Blocks from wizard
it create class splitted into header file and source file
and thats why i tried to divide code into

Node.h and Node.cpp
LinkedList.h and LinkedList.cpp
main.cpp

lastchance you suggest that i should put class and method definitions
in one header file ?
If they are template classes, then yes. Otherwise, no.

To signify something different I gave them filetype extensions .hpp rather than .h
There are two parties involved: human and IDE.

A compiler has to see the necessary bits when it is processing a translation unit. https://www.tutorialspoint.com/What-is-a-translation-unit-in-Cplusplus
The compiler/preprocessor does not care about filenames (although it might guess language based on source file's extension).

Human prefers familiar conventions and short blocks of code. If there are more than one human, they have to agree on conventions (so they don't have to guess).

IDE is full of IF x THEN y rules, like the "create class wizard" that conveniently and consistently fills in trivialities for you, or the syntax highlight. If your file naming convention differs, the IDE does not know what is the Right Thing. IDE cannot guess. You can probably define a new wizard for creating templates, if there is no such thing already.
@nowy20180820

You're not reading what we're telling you. Yes, for normal classes, it's good to split into header and source files.

However, for template classes, things are different. For template classes, you need the entire definition in the translation unit where the class is used (*) .

Effectively, that means putting the whole thing into header files that are included. You can split it between multiple included files, as lastchance and Handy Andy have explained, if you want to maintain the illusion of separating the implementation from the declaration.
Last edited on
nowy20180820 wrote:
When i create new class in Code::Blocks from wizard it create class splitted into header file and source file and thats why i tried to divide code into Node.h and Node.cpp ...

Note that a class template is not a class. It's a recipe for creating classes. Different rules apply.
Last edited on
Topic archived. No new replies allowed.