I'm trying to create a library for a school work, and I've been wondering if it is safe to declare a templated class on the main header file containing the class definition and method declarations, but then separating the method definitions in a different header file?
Because I have been able to do this in my example below, but I don't know if it will cause me some problems in the long run.
main program
// main.cpp
#include <iostream>
#include "declaration.hpp"
int main()
{
card<int> a(5);
std::cout<<a.getID()<<'\n';
return 0;
}
main header file
in this header file, only the class definition and the declaration of the method getID() is written but not it's definition, and by the end of the class I included the other header file that contains the method definitions.
// declaration.hpp
#ifndef DEC_HPP
#define DEC_HPP
#include <iostream>
template<typename T>
class card
{
public:
T id;
card(const int id) : id(id) {}
T getID();
};
#include "definition.hpp"
#endif
method definitions
This header file contains the method definition of getID() from the main header.
I also included the "declaration.hpp" in this header, and this is the part where I'm not so sure of, because I included both files together with each other.
// definitions.hpp
#ifndef DEF_HPP
#define DEF_HPP
#include <iostream>
#include "declaration.hpp"
template<typename T>
T card<T>::getID()
{
return id;
}
#endif
I have compiled this program and it's working on my machine, but I just wanted to know if this way of isolating my code will cause me some errors in the future, I don't want to put my templated class definitions in a cpp files because I find it hard to maintain.
This is indeed a better approach because it makes your code look simple and better. Moreover, it is the main reason why header file is used.
Your main header file will simply tell that what functions/classes are you using and without even viewing your code, anyone can guess if you are working correctly or not.
There wont be any safety issues at all.
This question already has answers here:
C++ Header Files, Code Separation
(4 answers)
Closed 8 years ago.
I've been writing in C++ lately and I'm getting confused with .cpp vs .h — when to use them and what should go in them. I've been reading that you should put function definitions in a separate .cpp file, and headers should be used for declarations, but how do I use the separate .cpp file? Do I #include it or what? I'm looking for clarification on .h and .cpp and what should go where and how to include separate .cpp files.
You should use .h file for function prototype and data type declarations and also for pre-processor directives, and .cpp files for definitions. For example, test.h might be look like
#define CONSTANT 123 // pre-processor directive
void myfunction(char* str);
and your test.cpp might look like
#include <stdio.h>
#include "test.h"
int main(int argc char **argv)
{
myfunction("Hello World");
return 0;
}
void myfunction (char* str)
{
printf("%s and constant %d", str, CONSTANT);
return;
}
Usually the class declaration goes into the (.h) header file, and the implementation goes in the .cpp file.
You include the header file in the cpp file, so all the functions will be recognized, and you should remember to use #ifndef in the header file to avoid errors (includes loops)
I have read in places like here that you have to include .h files and not .cpp files, because otherwise then you get an error. So for example
main.cpp
#include <iostream>
#include "foop.h"
int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}
foop.h
#ifndef FOOP_H
#define FOOP_H
int foo(int a);
#endif
foop.cpp
int foo(int a){
return ++a;
}
works, but if I replace #include "foop.h" with #include "foop.cpp" I get an error (Using Dev C++ 4.9.9.2, Windows):
multiple definition of foo(int)
first defined here
Why is this?
What include does is copying all the contents from the file (which is the argument inside the <> or the "" ), so when the preproccesor finishes its work main.cpp will look like:
// iostream stuff
int foo(int a){
return ++a;
}
int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}
So foo will be defined in main.cpp, but a definition also exists in foop.cpp, so the compiler "gets confused" because of the function duplication.
There are many reasons to discourage including a .cpp file, but it isn't strictly disallowed. Your example should compile fine.
The problem is probably that you're compiling both main.cpp and foop.cpp, which means two copies of foop.cpp are being linked together. The linker is complaining about the duplication.
When you say #include "foop.cpp", it is as if you had copied the entire contents of foop.cpp and pasted it into main.cpp.
So when you compile main.cpp, the compiler emits a main.obj that contains the executable code for two functions: main and foo.
When you compile foop.cpp itself, the compiler emits a foop.obj that contains the executable code for function foo.
When you link them together, the compiler sees two definitions for function foo (one from main.obj and the other from foop.obj) and complains that you have multiple definitions.
This boils down to a difference between definitions and declarations.
You can declare functions and variables multiple times, in different translation units, or in the same translation unit. Once you declare a function or a variable, you can use it from that point on.
You can define a non-static function or a variable only once in all of your translation units. Defining non-static items more than once causes linker errors.
Headers generally contain declarations; cpp files contain definitions. When you include a file with definitions more than once, you get duplicates during linking.
In your situation one defintion comes from foo.cpp, and the other definition comes from main.cpp, which includes foo.cpp.
Note: if you change foo to be static, you would have no linking errors. Despite the lack of errors, this is not a good thing to do.
You should just include header file(s).
If you include header file, header file automatically finds .cpp file.
--> This process is done by LINKER.
Because of the One Definition Rule (probably1).
In C++, each non-inline object and function must have exactly one definition within the program. By #includeing the file in which foo(int) is defined (the CPP file), it is defined both in every file where foop.cpp is #included, and in foop.cpp itself (assuming foop.cpp is compiled).
You can make a function inline to override this behavior, but I'm not recommending that here. I have never seen a situation where it is necessary or even desirable to #include a CPP file.
There are situations where it is desireable to include a definition of something. This is specially true when you try to seperate the definition of a template from the declaration of it. In those cases, I name the file HPP rather than CPP to denote the difference.
1: "(probably)" I say probably here because the actual code you've posted should compile without errors, but given the compiler error it seems likely that the code you posted isn't exactly the same as the code you're compiling.
Because your program now contains two copies of the foo function, once inside foo.cpp and once inside main.cpp
Think of #include as an instruction to the compiler to copy/paste the contents of that file into your code, so you'll end up with a processed main.cpp that looks like this
#include <iostream> // actually you'll get the contents of the iostream header here, but I'm not going to include it!
int foo(int a){
return ++a;
}
int main(int argc, char *argv[])
{
int x=42;
std::cout << x <<std::endl;
std::cout << foo(x) << std::endl;
return 0;
}
and foo.cpp
int foo(int a){
return ++a;
}
hence the multiple definition error
So I found that if you are compiling from Visual Studios you just have to exclude the included .cpp file from the final build (that which you are extending from):
Visual Studios: .cpp file > right click > properties > configuration properties >
general > excluded from build > yes
I believe you can also exclude the file when compiling from the command line.
I want to clarify something: including header files is not neccessary to make the linker understand what you want. You can just declare it and it will be linked fine.
main.cpp:
#include <iostream.h>
//not including "foop.cpp"!
int foo(int a);
int main(){
std::cout << foo(4) << std::endln;
}
foop.cpp:
int foo(int a){
return a++;
}
I don't encourage doing like this, but know that headers are not some magic which you have to follow to make the code compile.
Using ".h" method is better
But if you really want to include the .cpp file then make foo(int) static in foo.cpp
I began to write my program in a single cpp-file but now I have too much code so I decided to separate it. But the problem is that I have many constants, includes and some other things that I want to have all in one place. Unfortunately, all of them are needed by dependent parts of code so I can't do it with usual include files.
What would help me?
(I write under Linux and compile with command-line)
(Sorry for my English :))
As Hristo said, you should generally write the definitions in header files and write the implementation in the source code files.
To answer your question however:
But the problem is that I have many constants, includes and some other things that I want to have all in one place.
What I've typically done is create a single file called something like "common.h" or "defs.h" (I took the idea from Doom...) and that file has many defines that you find you need throughout your entire program. If you are using constants, declare the constants in the header file like so:
extern const int MAX_SOMETHING;
extern const bool TRUTH_VALUE;
and make a complementary source file (defs.cpp or common.cpp) that defines these constants:
const int MAX_SOMETHING = 5;
const bool TRUTH_VALUE = true;
so now when you include the common/defs.h in other source files, the extern keyword will tell that source file that the definition is in another source file (its in the common/defs.cpp) so it will find the definition in there, and you can use it anywhere where you have included common/defs.cpp.
In most projects definitions are in header files and implementations are in source code files. However the implementations of template functions must be in the header files because they must be visible to all source files using them. Variables should be defined extern in header files and be declared in source files. Constants may also be declared in header files static.
Example:
Foo.h
#pragma once
class Foo{
public:
void bar();
template<class Type>
void increment(Type &a){
++a;
return;
}
};
extern Foo theFoo;
static const int five=5;
Foo.cpp
#include "Foo.h"
#include <iostream>
void Foo::bar(){
std::cout<<"Foo::bar called"<<std::endl;
return;
}
Foo theFoo;
Main.cpp
#include "Foo.h"
#include <iostream>
int main(){
theFoo.bar();
std::cout<<five<<std::endl;
return 0;
}
I'm writing a C++ Package for later use using Code::Blocks.
The project structure looks like this:
cNormal\
cNormal.cdp
src\
main.cpp # for testing purpose
cnormal_defs.h # important compiler definitions
cnormal_storage.h # includes all .h files from "./storage"
storage\
cnarray.h
cnarray.cpp
cnstack.h
cnstack.cpp
bin\
obj\
The cnormal_storage.h:
// cnormal_storage.h
// *****************************************************************
// Includes all necessary headers for the cNormal storage subpackge.
//
#ifndef _cNORMAL_STORAGE_H_
#define _cNORMAL_STORAGE_H_
#include "storage/cnarray.h"
#include "storage/cnstack.h"
#endif // _cNORMAL_STORAGE_H_
To test the classes, i create a main-function in main.cpp.
// main.cpp
// *****************************************************************
// The main-file.
//
#include <iostream>
#include "cnormal_storage.h"
using namespace std;
int main() {
cnArry<int> arr(10);
arr[9] = 999;
arr[0] = 0;
cout << arr[9] << endl;
cout << arr.getLength();
}
But the compiler (gcc) gives me undefined reference to ... errors about cnArray.
Now, the cnarray.cpp includes cnarray.h (as it is the implementation file), so using
#include "storage/cnarray.cpp" works just fine.
It seems like the compiler can't find the implementation of cnarray.h which is located in cnarray.cpp.
I assume it's because of the folder-structure, can you tell me how I can fix this ?
Even adding src\storage to the include directives does not fix it. (And I also don't want to add it to the include-paths as this would be very unhandy for a package.)
Can you post the compilation command that you use?
Seems like you are compiling only main.cpp and not compiling (and thus linking) the other .cpp files.
I could spot the error now, cnArray.h declared a template class and template classes cannot be implmented in another file than they are declared, because the compiler must know about the implementation when compiling, not when linking.
I have found a workaround on the internet to #include the implementation in the headerfile, but exclude the implementation file from compiling.
This works just fine now.
Cheers