Is it necessary to #include .cpp file?

Good morning, all!

I have a question about h. file and .cpp file.
For example, I have three files, one head file(Chain_ChainNode.h) and two source file(Chain_ChainNode.cpp and main.cpp.

Chain_ChainNode.h declared the class Chain and ChainNode.
Chain_ChainNode.cpp implemented the functions in Class Chain.
Main.cpp has the main function.

This program can only be compiled when I include Chain_ChainNode.cpp in the Main.cpp as the following. But I don't think it's necessary to include the source file in 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
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
//Chain declaration
//Chain_ChianNode.h
#ifndef CHAIN_H
#define CHAIN_H

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

template <typename T> class Chain;

template <typename T>
class ChainNode {	
	T data;
	ChainNode<T> *link;
public:
	friend Chain<T>;
};

template <typename T>
class Chain {
	ChainNode<T> *first;
public:
	Chain() {first = 0;} 
	~Chain();
	bool IsEmpty() const;
	int Length() const;
	bool Find(int k, T& x) const;
	int Search(const T& x) const;
	Chain<T>& Delete(int k, T& x);
	Chain<T>& Insert(int k, const T& x);
	void Output(std::ostream& out) const;
};


#endif ///:~

==========================================================================
//implementaion
//Chain_ChainNode.cpp
#include "stdafx.h"
#include "Chain_ChainNode.h"
#include <iostream>

using namespace std;

//functions of Chain

template <typename T>	//delete all nodes
Chain<T>::~Chain()
{
	ChainNode<T> *next;
	while (first)
	{
		next = first->link;
		delete first;
		first = next;
	}
}

template <typename T>
bool Chain<T>::IsEmpty() const 
{
	return (first == 0);
}

template <typename T>	//Length of the Chain
int Chain<T>::Length() const
{
	ChainNode<T> *current = first;
	int len = 0;
	while(current)
	{
		len++;
		current = current->link;
	}
	return len;
}

template <typename T>
bool Chain<T>::Find(int k, T& x) const
{
	if(k < 1) return false;
	ChainNode<T> *current = first;
	int index = 1;	//current index
	while (index < k && current)
	{
		current = current->link;
		index++;
	}
	if(current) {x = current->data; return true;}
	return false;
}

template <typename T>
int Chain<T>::Search(const T& x) const
{
	ChainNode<T> *current = first;
	int index = 1;
	while (current && current->data != x)
	{
		current = current->link;
		index++;
	}
	if(current) return index;
	return 0;
}

template <typename T> //Output
void Chain<T>::Output(ostream& out) const
{
	ChainNode<T> *current;
	for(current = first; current; current = current->link)
	{
		out << current->data << " ";
	}
}

template <typename T>
ostream& operator<<(ostream& out, const Chain<T>& x)
{
	x.Output(out);
	return out;
}

template <typename T>	//delete one element, delete element k and put it to x
Chain<T>& Chain<T>::Delete(int k, T& x)
{
	if(k < 1 || !first)	//不存在第K个元素
		throw OutOfBound();
	ChainNode<T> *p = first;
	if(k == 1)
		first = first->link;
	else {
		ChainNode<T> *q = first;
		for(int index = 1; index < k - 1 && q; index++) q = q->link;	//q points to element k-1 address
		if(!q || !q->link)
			thorw OutOfBounds();
		p = q->link;	// p points element k address
		q->link = p->link;	//q->link was pointing to p, and now points to p->link
		x = p->data;
		delete p;
	}
		return *this;	
}

template <typename T>	//Insert 
Chain<T>& Chain<T>::Insert(int k, const T& x)
{
	if(k < 0) throw OutOfBounds();

	ChainNode<T> *p = first;
	for(int index = 1; index < k && p; index++)
		p = p->link;	//move to element k
	if(k > 0 && !p) throw OutOfBounds();
	//Insert x after k
	ChainNode<T> *y = new ChainNode<T>;
	y->data = x;
	if(k) {
		y->link = p->link;
		p->link = y;
	}
	else {
		y->link = first;
		first = y;
	}
	return *this;
}

================================================================================
// PracticeProject.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "Chain_ChainNode.h"
#include "xcept.h"
#include "Chain_ChainNode.cpp" //This is my question: Shoud main.cpp file include this source file?
using namespace std;


int main () 
{
	try {
		Chain<int> L;
		L.IsEmpty();
		cout << "Lenth = " << L.Length() << endl;
		L.Insert(0,100).Insert(1,101);
		cout << "List is : " << L << endl;
	}
	catch(...) {
		cerr << "An exception has occurred" << endl;
	}
}

While technically possible, it goes against common practice to #include a .cpp file. Just put template definitions into the .h file, which is where they are supposed to be.
Last edited on
Thanks for your replay!
But Is it a good idea to put template definitions into the .h header file? I find it every book suggests that it's better to separate the declaration file and definition file.
Please let me put a example from <<Thinking in C++>>



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
=====================================================//Header file//
//: C06:Stash2.h
#ifndef STASH2_H
#define STASH2_H

class Stash {
  int size;      // Size of each space
  int quantity;  // Number of storage spaces
  int next;      // Next empty space
  // Dynamically allocated array of bytes:
  unsigned char* storage;
  void inflate(int increase);
public:
  Stash(int size);
  ~Stash();
  int add(void* element);
  void* fetch(int index);
  int count();
};
#endif // STASH2_H ///:~

=====================================================
//definition file//
//: C06:Stash2.cpp {O}

#include "Stash2.h"
#include "../require.h"
#include <iostream>
#include <cassert>
using namespace std;
const int increment = 100;

Stash::Stash(int sz) {
  size = sz;
  quantity = 0;
  storage = 0;
  next = 0;
}

int Stash::add(void* element) {
  if(next >= quantity) // Enough space left?
    inflate(increment);
  // Copy element into storage,
  // starting at next empty space:
  int startBytes = next * size;
  unsigned char* e = (unsigned char*)element;
  for(int i = 0; i < size; i++)
    storage[startBytes + i] = e[i];
  next++;
  return(next - 1); // Index number
}

void* Stash::fetch(int index) {
  require(0 <= index, "Stash::fetch (-)index");
  if(index >= next)
    return 0; // To indicate the end
  // Produce pointer to desired element:
  return &(storage[index * size]);
}

int Stash::count() {
  return next; // Number of elements in CStash
}

void Stash::inflate(int increase) {
  require(increase > 0, 
    "Stash::inflate zero or negative increase");
  int newQuantity = quantity + increase;
  int newBytes = newQuantity * size;
  int oldBytes = quantity * size;
  unsigned char* b = new unsigned char[newBytes];
  for(int i = 0; i < oldBytes; i++)
    b[i] = storage[i]; // Copy old to new
  delete [](storage); // Old storage
  storage = b; // Point to new memory
  quantity = newQuantity;
}

Stash::~Stash() {
  if(storage != 0) {
   cout << "freeing storage" << endl;
   delete []storage;
  }
} ///:~

=====================================================
//Main.cpp file//
//: C06:Stash2Test.cpp

//{L} Stash2
// Constructors & destructors
#include "Stash2.h"
#include "../require.h"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;

int main() {
  Stash intStash(sizeof(int));
  for(int i = 0; i < 100; i++)
    intStash.add(&i);
  for(int j = 0; j < intStash.count(); j++)
    cout << "intStash.fetch(" << j << ") = "
         << *(int*)intStash.fetch(j)
         << endl;
  const int bufsize = 80;
  Stash stringStash(sizeof(char) * bufsize);
  ifstream in("Stash2Test.cpp");
  assure(in, " Stash2Test.cpp");
  string line;
  while(getline(in, line))
    stringStash.add((char*)line.c_str());
  int k = 0;
  char* cp;
  while((cp = (char*)stringStash.fetch(k++))!=0)
    cout << "stringStash.fetch(" << k << ") = "
         << cp << endl;
} ///:~





From this example, we can clearly see that the Stash2.cpp file which is the definition file was not included in the main file. So How can the compiler find the definition according to declaration in Stash.h?
The Stash example doesn't involve templates.
So if I wanna use templates, I have to put all definitions to .h file, or include that .pp source file?
Yes. Look at the boost libraries; they are mostly header-only. Even the gigantic ones like boost.spirit
#include "stdafx.h" why is this one wrapped by ""
#include <iostream> but this one wrapped by <>
Because iostream is a standard header file. stdafx.h is part of your project.
Hello, Cubbi! What is the boost libraries??javascript:editbox1.editPreview()
why do I see chinese characters in your source code? 求QQ。
If you are going to include the cpp, do it in the header file, not in main.cpp
1
2
3
4
5
6
7
8
// class.h
template < typename t>
class C
{
  func(void)
};

#include class.cpp 

1
2
3
// class.cpp
template <typename T>
void C<T>::func(void) { /* make money */ }


1
2
// main.cpp
#include "class.h" 
Last edited on
@LowestOne
Er, no. If you are going to #include a .cpp file, do it in another .cpp file, never in a header.


@akluffy
The .cpp files get compiled to actual code. An individual .cpp file gets compiled to an "object file". Your object files are "linked" together to create an executable.

Header files do not get compiled. They just describe the stuff you will find in a .cpp file.

So, for example,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// greeting.hpp
// This file is not compiled.

#pragma once
#ifndef GREETING_HPP
#define GREETING_HPP

#include <string>

namespace greeting
  {

  void hello( const std::string& name = "world" );

  } // namespace greeting

#endif 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// greeting.cpp
// This file gets compiled

#include "greeting.hpp"

#include <iostream>
using namespace std;

namespace greeting
  {

  void hello( const string& name )
    {
    cout << "Hello " << name << "!\n";
    }

  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// main.cpp
// This file gets compiled

#include <iostream>
#include <limits>
#include <string>
using namespace std;

#include "greeting.hpp"
using namespace greeting;

int main()
  {
  hello();

  cout << "What is your name? ";
  string name;
  cin >> name;
  cin.ignore( numeric_limits <streamsize> ::max(), '\n' );

  hello( name );

  return 0;
  }

Now we can play.

Given
    C:\Prog> dir/b
    greeting.cpp
    greeting.hpp
    main.cpp
    C:\Prog>
Compile
    C:\Prog> gcc -c main.cpp
    C:\Prog> gcc -c greeting.cpp
    C:\Prog> dir/b
    greeting.cpp
    greeting.hpp
    greeting.o
    main.cpp
    main.o
    C:\Prog>
Link
    C:\Prog> gcc main.o greeting.o -o hello
    C:\Prog> dir/b
    greeting.cpp
    greeting.hpp
    greeting.o
    hello.exe
    main.cpp
    main.o
    C:\Prog>
Execute
    C:\Prog> hello
    Hello world!
    What is your name? Silly Billy
    Hello Silly!
    C:\Prog>


Hope this helps.
LowestOne wrote:
If you are going to include the cpp, do it in the header file, not in main.cpp


Now, I am no expert with templates, but I thought the usual practice (and as Cubbi says) was not to include .cpp files.

I know you are saying if, but in your example, why wouldn't the code in class.cpp be part of the header file ?

Now I am not trying to be pedantic, and I am aware that you probably have much more knowledge & experience than me, but I am asking why you would promote such an idea?

I am asking this for my education as much as anyone else's, and am hoping it doesn't come across as overt criticism, rather a simple query.

Edit : Ninja'd
Last edited on
akluffy wrote:
Hello, Cubbi! What is the boost libraries??

http://www.boost.org
Well, okay, guess I am wrong.

But why? I thought include just included the file. These two examples would end the same
1
2
3
4
5
// my_header.h

int func(void);

int func(void) { return 0; }


1
2
3
4
5
6
7
8
// my_header.h

int func(void);

#include my_header.cpp

// my_header.cpp
int func(void) { return 0; }


I probably know less than you all do anyway :). Just spouting off what I read in a book. The only reason it gave for this was to just make things look a little more clean. The downside is that you have to remember that you could never compile the source into an object.

Topic archived. No new replies allowed.