I'm working on a fairly large project (3D graphics engine) and I've run into some trouble while restructuring the code a bit. I want to have all of my classes implemented in single files (only have .hpp rather than having both a .cpp and .hpp file for each class). I don't have a specific reason for doing it this way other than just wanting to, but I'm hoping to avoid discussions over what C++ best practices are.
When I do it this way I get a series of multiple definition errors that look like this:
/tmp/ccztDQam.o: In function `Point3DH::normalize()':
Renderer.cpp:(.text+0x736): multiple definition of `Point3DH::normalize()'
/tmp/ccawpiuU.o:main.cpp:(.text+0x1a6de): first defined here
/tmp/ccztDQam.o: In function `Point3DH::dot(Point3DH, Point3DH)':
Renderer.cpp:(.text+0x79e): multiple definition of `Point3DH::dot(Point3DH, Point3DH)'
/tmp/ccawpiuU.o:main.cpp:(.text+0x1a746): first defined here
/tmp/ccztDQam.o: In function `Point3DH::cross(Point3DH, Point3DH)':
Renderer.cpp:(.text+0x7d6): multiple definition of `Point3DH::cross(Point3DH, Point3DH)'
/tmp/ccawpiuU.o:main.cpp:(.text+0x1a77e): first defined here
...
The issue comes when the classes start including each other and code is repeated multiple times. It seems that header guards are not sufficient as explained in this answer. I'm wondering if there is any way to get around this or an alternate way to achieve the goal.
The project is organized into modules (folders) such as geometry or polygon which contain relevant classes so include paths go to the parent directory and then into the correct module and class
For reference, here is what one of the files looks like (./graphics/Raster.hpp):
#ifndef GRAPHICS_RASTER
#define GRAPHICS_RASTER
#include "../graphics/Colour.hpp"
#include <vector>
class Raster {
private:
std::vector<Colour> image;
std::vector<double> zBuffer;
int width;
int height;
public:
Raster(int, int, Colour);
void setPixel(int, int, double, Colour);
int getWidth();
int getHeight();
};
#endif
#ifndef GRAPHICS_RASTER_IMPLEMENTATION
#define GRAPHICS_RASTER_IMPLEMENTATION
#include "../graphics/Colour.hpp"
#include <vector>
#include <limits>
Raster::Raster(int width, int height, Colour clear) :
image(std::vector<Colour>(width*height, clear)),
zBuffer(std::vector<double>(width*height, -std::numeric_limits<double>::max())),
width(width),
height(height)
{}
void Raster::setPixel(int x, int y, double z, Colour c) {
if(x < 0 || x >= width || y < 0 || y >= height) return;
if(z <= zBuffer[(height - y - 1)*width + x]) return;
image[(height - y - 1)*width + x] = c;
zBuffer[(height - y - 1)*width + x] = z;
}
int Raster::getWidth() {return width;}
int Raster::getHeight() {return height;}
#endif
If you for some reason want to implement everything in header files, you have to make all your functions inline. Functions defined in class definitions are implicitly inline. Functions defined out-of-class have to be declared with inline keyword explicitly.
That's what you have to do with every definition that you have in the "implementation" section of your header - add explicit inline keyword to every function definition. E.g.
inline void Raster::setPixel(int x, int y, double z, Colour c) {
if(x < 0 || x >= width || y < 0 || y >= height) return;
if(z <= zBuffer[(height - y - 1)*width + x]) return;
image[(height - y - 1)*width + x] = c;
zBuffer[(height - y - 1)*width + x] = z;
}
and so on.
Of course, you can also move all your member function definitions into class definition (which will make them inline), but that will preclude such distinctly separated two-section header structure as you have now. I don't know how important it is to you.
Every time your header is included in a cpp file, you create a new copy of the implementation.
You need to make sure that the implementation is only used in one cpp file - or inline every method.
This guide have good ideas on doing that:
https://github.com/nothings/stb/blob/master/docs/stb_howto.txt
examples:
https://github.com/nothings/stb
Basically:
1-make a #define UNIQUE_NAME_IMP and #define UNIQUE_NAME_HEADER to make implementation and declaration visible on different files by using:
your implementation:
#ifdef _DECL_
type declaration
function prototype
#endif
#ifdef _IMPL_
code
#endif
and in another file that will use it:
#define _DECL_
#include <my_header.h>
code...
...
//use this only once to avoid
//duplicate symbol like you mentioned in your post.
#define _IMPL_
#include <my_header.h>
2-avoid memory allocation, make your functions use the memory you pass on with your structures.
3-avoid external dependencies. Each dependency will make you use flags or create requirements to comply before using your header...
4-use "static". This makes the implementation private to the source file that creates it.
Related
This question already has answers here:
error: Class has not been declared despite header inclusion, and the code compiling fine elsewhere
(9 answers)
Closed 7 years ago.
You could have forgot to include problemclass.h from the file where you are using ProblemClass.
You could have misspelled the name of ProblemClass either in its own header file or in the place where you are using it. This can be
hard to spot if it is a capitalization error such as writing
Problemclass or problemClass instead of ProblemClass.
You could have copy-pasted your inclusion guard #defines from one header file to another and then forgot to change the defined names.
Then only the first of those two included header files would take
effect.
You could have placed ProblemClass in a namespace A, in which case you must refer to ProblemClass as A::ProblemClass if you are referring
to it from outside the namespace A.
You may be using templates and not expecting two-phase lookup to work the way it does.
You could have misspelled the file name in your include. The compiler would not report an error on that if you also have an old
version of that file under the misspelled name.
You could have made ProblemClass a macro that only gets defined after you include problemclass.h, in which case what you see as
ProblemClass gets replaced by something else by the macro
preprocessor.
You could have defined ProblemClass in a header file other than problemclass.h and then problemclass.h actually defines something
else.
The above was taken from another similar question, I found the points useful but none actually solved my problem, stated hereunder:
I'm creating a natural language processor for a robot, giving the software various objects to represent real world items in its environment (Blocks world for now), one of the objects defined in Block:
/*
* Block.h
*
* Created on: 11 Mar 2015
* Author: Edward
*/
#ifndef BLOCK_HPP_
#define BLOCK_HPP_
#include "typedefinitions.h"
#include "dynamixel.h"
#include "BasicRobotFunctions.hpp"
class Block {
public:
bool grounded;
//TODO position is a deprecated variable, replace with distance from
//pos position;
int number;
int distance;
int object_brightness;
Block(BasicRobotFunctions basic);
virtual ~Block();
void setBrightness(int brightness);
void setGrounded(bool ground);
//void setPosition(int x, int y);
void setDistance(int number);
void setNumber(int number);
//pos getPosition();
int getNumber();
int getDistance();
bool getGrounded();
int getBrightness();
int lookAround(BasicRobotFunctions basic);
};
#endif /* BLOCK_H_ */
with source file:
/*
* Block.cpp
*
* Created on: 11 Mar 2015
* Author: Edward
*/
#include "Block.hpp"
#define DEFAULT_PORTNUM 3 // COM3
#define DEFAULT_BAUDNUM 1 // 1Mbps
Block::Block(BasicRobotFunctions basic) {
grounded = false;
number = Block::lookAround(basic);
}
Block::~Block() {}
void Block::setGrounded(bool ground){
grounded = ground;
}
/*
void Block::setPosition(int x, int y){
position.x = x;
position.y = y;
}*/
void Block::setDistance(int dist){
distance = dist;
}
void Block::setNumber(int num){
number = num;
}
bool Block::getGrounded(){
return grounded;
}
/*
pos Block::getPosition(){
return position;
}*/
int Block::getNumber(){
return number;
}
int Block::getDistance(){
return distance;
}
int Block::getBrightness(){
return object_brightness;
}
//TODO Arrange function to incorporate Turn() in BasicRobotFunctions
int Block::lookAround(BasicRobotFunctions basic){
int num = 0;
dxl_initialize(DEFAULT_PORTNUM,DEFAULT_BAUDNUM);
for(int i = 0;i<360;i++){
dxl_write_word(11,32,-255);
dxl_write_word(11,30,200);
basic.Step(1);
dxl_write_word(11,32,255);
dxl_write_word(11,30,100);
if(dxl_read_byte(100,32) >= dxl_read_byte(100,52)){
num++;
}
}
dxl_terminate();
return num;
}
void Block::setBrightness(int bright){
object_brightness = bright;
}
I am however receiving the following compilation error from the constructor and from the turnAround(BasicRobotFunctions) method:
In file included from Robot.hpp:11,
from BasicRobotFunctions.hpp:12,
from main.cpp:8:
Block.hpp:23: error: expected `)' before 'basic'
Block.hpp:35: error: 'BasicRobotFunctions' has not been declared
make.exe: *** [main.o] Error 1
Having checked my other classes utilizing objects as variables I get the same error.
In response to the points in the quote:
- BasicRobotFunctions.hpp is included
- the class name is spelt the same in all different instances mentioning it
- I didn't copy paste any inclusion guard
- I didn't use any namespaces in the project
- Nor am I using any templates
- the file name isn't misspelled in my include
- I haven't defined any macros in the program
- I made sure every class was defined in its own header file
Is there any other issue my system could possibly have, any mistake I'm making or simply anything I'm doing which is bad programming practice here?
The cause of your problem:
You have a header file circular dependency problem.
main.cpp includes BasicRobotFunctions.hpp
which includes Robot.hpp
which includes Block.hpp
which includes BasicRobotFunctions.hpp.
If your header files are properly guarded against multiple inclusion (which it seems that they are), Block.hpp won't see the definitions of BasicRobotFunctions.hpp because it is already in the middle of including it.
How to spot the problem:
The source of this problem is apparent in the compilation error message and in your Block.hpp file.
The compiler is reporting an error in Block.hpp, and it is describing line by line how it got to that file via inclusions. The source to your Block.hpp file makes it clear that it is trying to include BasicRobotFunctions.hpp.
The fix:
In your case, you can modify your method signatures in Block.hpp to use a (perhaps constant) reference to the BasicRobotFunctions type, and then forward declare the type. This allows you to eliminate the dependency on the BasicRobotFunctions.hpp header file. (Block.cpp would likely need to include both Block.hpp and BasicRobotFunctions.hpp.)
//...
#include "typedefinitions.h"
#include "dynamixel.h"
class BasicRobotFunctions; // Forward declaration
//...
Block(const BasicRobotFunctions &basic);
//...
int lookAround(const BasicRobotFunctions &basic);
//...
You may be able to avoid this problem in the future by minimizing what headers are required to allow your header file to compile. This means your header file should:
Use forward declarations to types that are used.
Use references to forward declared types.
You can check that your header file has minimized its dependencies by making sure it compiles by itself. I accomplish this by including the header file first in a corresponding source file, and then make sure the source file compiles.
// Foo.cpp
#include "Foo.hpp"
//...
Well you can put a forward declaration before the class as
class BasicRobotFunctions;
class Block {
public:
bool grounded;
//TODO position is a ...
but this kind of error means that the #include "BasicRobotFunctions.hpp"
don't declare the BasicRobotFunctions. It's possible a trouble with code guards?
The circular inclusion can be solved using the forward declaration, putting correct guards in headers and moving some includes to source files.
I have been just tweaking around my game (putting class declaration in *.h files with their definition in the corresponding .cpp object files), but I don't quite understand when I have to use 'inline' keyword next to the method definitions and when I don't. Let me show you:
//shape.h
//header guards and includes in here
class shape
{
private:
char type;
int verticies[4][2];
int centre[2];
int radius;
public:
shape(int coordinates[4][2]);
shape(int coords[2], int r);
void Change(int coordinates[4][2]);
void Change(int coords[2], int r);
//more functions...
};
//shape.cpp
#include "shape.h"
inline shape::shape(int coordinates[4][2])//Constructor for a rectangle shape
{
for (int i=0; i<8; i++) //copy arguments to class
verticies[i/2][i%2]=coordinates[i/2][i%2];
//calculate centre of the rectangle
centre[0]=(coordinates[0][0]+coordinates[2][0])/2;
centre[1]=(coordinates[0][1]+coordinates[2][1])/2;
}
inline shape::shape(int coords[2], int r)//Constructor for a circle shape
{
type='C';
centre[0]=coords[0];
centre[1]=coords[1];
radius=r;
}
inline void shape::Change(int coordinates[4][2])//change coordinates of a rectangle shape
{
if (type=='C') return;//do nothing if a shape was a circle
for (int i=0; i<8; i++)
verticies[i/2][i%2]=coordinates[i/2][i%2];
centre[0]=(coordinates[0][0]+coordinates[2][0])/2;
centre[1]=(coordinates[0][1]+coordinates[2][1])/2;
if(verticies[0][0]-verticies[1][0]==0 || verticies[0][1]-verticies[1][1]==0) type='S'; else type='R';
}
inline void shape::Change(int coords[2], int r)//change coordinates for a circle shape
{
if (type=='R' || type=='S') return; //do nothing if a shape was not a circle
centre[0]=coords[0];
centre[1]=coords[1];
radius=r;
}
//and so on...
Not having an inline keyword would result in: "multiple definition of `shape::shape(int (*) [2])' " error. However on other occasions with other classes use of 'inline' was unneccesary. So my question is: when do I have to use 'inline' keyword and why is it important anyway?
Edit: So I have been informed that using inline in this situation is a bad Idea. Therefore what is a proper way to implement source and header files?
The inline keyword is important when you define a non-template function in a header file, but outside a class declaration. It avoids the multiple definition issue when a header is included in multiple places.
Other than that, it's not much use these days. It's technically still supposed to indicate that you want a function to use inline expansion -- i.e. instead of actually calling it (which presents a small overhead), the compiler just drops copies of the entire function body into whatever location it gets called from. (It's an invaluable optimisation for very small functions, such as accessor methods.) In reality though, compilers tend to figure out what should and shouldn't be inlined on their own, so it takes the keyword as little more than a hint.
In the version of the code you posted, inline key is completely unnecessary and actually harmful. In this version you have to remove all inline keywords from the code you posted to be able to properly compile and link it. What you posted will typically cause linker errors due to missing function definitions.
inline keyword becomes necessary if you move all your function definitions into the header file.
So, this is the simple rule you have to follow with inline keyword and member functions: If you define your member function in the header (.h) file, use inline keyword. If you define your member function in implementation (.cpp) file, don't use inline keyword.
I have the following 3 files (1 *.cpp and 2 *.hpp) :
the main program file:
// test.cpp
#include<iostream>
#include"first_func.hpp"
#include"sec_func.hpp"
int main()
{
double x;
x = 2.3;
std::cout << sec_func(x) << std::endl;
}
-
the first_func.hpp header:
// first_func.hpp
...
double first_func(double x, y, x)
{
return x + y + x;
}
-
the sec_func.hpp header:
// sec_func.hpp
...
double sec_func(double x)
{
double a, b, c;
a = 3.4;
b = 3.3;
c = 2.5;
return first_func(a,b,c) + x;
}
How do I properly call first_func from within the sec_func.hpp file?
For most functions, the implementation should reside in a compilation unit, that is a file that is going to be compiled by itself and compiled once.
Headers are not to be compiled by themselves*, instead they are included by multiple compilation units.
That's why your function definitions should reside in compilation units (like .cpp), not in headers. Headers should contain only the declarations (i.e. without the body), just enough so that other compilation units would know how to call them.
For completeness, the functions that generally need to be defined in headers (as an exception) are:
inline functions
template functions** (classes too)
Footnotes:
* headers can actually be pre-compiled, but that's a solution for speeding up compilation and it doesn't alter their purpose; don't get confused by that.
** you can put template function definitions outside of the headers if you use explicit template instantiation, but that's a rare case; the point is that every compilation unit that wants to instantiate a template (apply arguments to it) needs to have its complete definition, that's why template function definitions go into headers too.
It's a bad practice to place function definition to .hpp files. You should place only function prototypes there. Like this:
first_func.hpp:
double first_func(double x, double y, double x);
first_func.cpp:
double first_func(double x, double y, double x)
{
return x + y + x;
}
The same for second func.
And then, wherever you want to call your first_func, you just include corresponding first_func.hpp in that cpp module, and write the call.
Thus, every your module consists of hpp with all declarations, and cpp with definitions (that is, the bodies). When you need to reference something from this module, you include its hpp and use the name (of constant, variable, function, whatever).
And then you must link everything together:
gcc main.cpp first_func.cpp second_func.cpp -o program
To define a function in a header, you must mark it inline to prevent multiple definitions.
If you want to do this instead of separating the implementation to a separate file, you'll need to provide a prototype before calling the function (either by including the header (prefered) or declaring the function yourself).
// sec_func.hpp
#include "first_func.hpp"
//or
double first_func(double x, y, x); //declaration
double sec_func(double x)
{
double a, b, c;
a = 3.4;
b = 3.3;
c = 2.5;
return first_func(a,b,c) + x;
}
I developed my own Matrix class. Constructor reads a matrix from file. Matrix has free cells and "walls". Also constructor reads start and finish points for Breadth first search (to find the shortest way from Start_point to Finish_Point).
Here is code of header:
//MyMatrix.h file
#ifndef __MYMATRIX_H__
#define __MYMATRIX_H__
#include <tchar.h>
#include <iostream>
#include <deque>
//using namespace std;
#define MAX_MATRIX_SIZE 1000
#define FREE_CELL_SIGNIFICATION '0'
#define BALL_SIGNIFICATION 'B'
#define UP_SIGNIFICATION 'U'
#define DOWN_SIGNIFICATION 'D'
#define LEFT_SIGNIFICATION 'L'
#define RIGHT_SIGNIFICATION 'R'
#define START_POINT_SIGNIFICATION 'S'
#define FINISH_POINT_SIGNIFICATION 'F'
typedef std::pair<int,int> Field_Point_Type;
//#define IS_RIGHT_NEIGHBOUR_REACHABLE(Current_Point) (((Current_Point.second+1) <= Column_Count)&&((Matrix_Field[Current_Point.first][Current_Point.second+1]==FREE_CELL_SIGNIFICATION)||(Matrix_Field[Current_Point.first][Current_Point.second+1]==FINISH_POINT_SIGNIFICATION))) ? true : false;
class Matrix {
private:
int Column_Count; //Cols
int Row_Count;//Rows
char** Matrix_Field;
Field_Point_Type Start_Point;
Field_Point_Type Finish_Point;
bool Matrix_Is_Correct;
public:
Matrix(_TCHAR* Input_File_Name);
int Breadth_first_search(unsigned int Start_X,unsigned int Start_Y,unsigned int Finish_X,unsigned int Finish_Y);
~Matrix();
inline int IS_RIGHT_NEIGHBOUR_REACHABLE(Field_Point_Type Current_Point);
};
//MyMatrix.cpp file
...
inline int Matrix::IS_RIGHT_NEIGHBOUR_REACHABLE(Field_Point_Type Current_Point)
{
return (((Current_Point.second+1) <= Column_Count)&&((Matrix_Field[Current_Point.first][Current_Point.second+1]==FREE_CELL_SIGNIFICATION)||(Matrix_Field[Current_Point.first][Current_Point.second+1]==FINISH_POINT_SIGNIFICATION))) ? true : false;
}
...
I'd like to define are the neighbour cells free for the next step of algorithm.
Of course I can use such code for this:
if (((Current_Point.second+1) <= Column_Count)&&((Matrix_Field[Current_Point.first][Current_Point.second+1]==FREE_CELL_SIGNIFICATION)||(Matrix_Field[Current_Point.first][Current_Point.second+1]==FINISH_POINT_SIGNIFICATION))) {
//Adding of right cell to deque...
...
}
but it looks ugly. I am going to add such checks for left, up and down cells.
I'd like to implement inline functions (like this: inline int IS_RIGHT_NEIGHBOUR_REACHABLE(Field_Point_Type Current_Point);).
if (IS_RIGHT_NEIGHBOUR_REACHABLE(Current_Point)) {
//Adding of right cell to deque...
...
}
It looks much better!
But I haven't use such definition of inline function before and discovered it accidentally.
Is it good programming style?
Is it better to develop simple int IS_RIGHT_NEIGHBOUR_REACHABLE(Field_Point_Type Current_Point); method within my class?
Is it better to leave such check:
if (((Current_Point.second+1) <= Column_Count)&&((Matrix_Field[Current_Point.first][Current_Point.second+1]==FREE_CELL_SIGNIFICATION)||(Matrix_Field[Current_Point.first][Current_Point.second+1]==FINISH_POINT_SIGNIFICATION))) {
//Adding of right cell to deque...
...
}
I don't think we have an established "good style" yet. Compilers capable of inlining functions from a separately compiled .cpp file are rather recent models of the most popular compilers.
Until a couple of years ago you had to have all inline functions in a .h file, so the compiler could see it while compiling the call. If your compiler is not the latest model, that might still be the rule.
inline Functions need to be implemented in header files. If it really improves your performance you need to check by benchmarks.
However good compilers might inline functions automatically (hopefully).
To your question, I would prefer to have many small functions. They are normally easier to maintain and can be checked individually if they are correct.
I'm having a headerfile called cnVector.h whose implementation is written in cnVector.cpp.
Those two files are located in the same directory.
cNormalCBP/
+ src/
+ cNormal/
+ cnUtils/
- cnVector.h
- cnVector.cpp
- main.cpp
The header contains a simple class definition.
class cnVector {
public:
cnVector(double, double, double);
inline cnVector cross(const cnVector&) const;
};
The implementation in the .cpp file is as follows:
#include "cnVector.h"
/* constructor */ cnVector::cnVector(double x, double y, double z)
: x(x), y(y), z(z) {
}
cnVector cnVector::cross (const cnVector& vOther) const {
return cnVector(
y * vOther.z + z * vOther.y,
z * vOther.x + x * vOther.z,
x * vOther.y + y * vOther.x );
}
Now, the following code from main.cpp breaks at line 3 because of an undefined reference to cnVector::cross(cnVector const&) const;
Note how the constructor-implementation is recognized, but not the cnVector::cross method.
int main() {
cnVector v1(1, 0, 0), v2(0, 1, 0);
cnVector v3 = v1.cross(v2);
}
I also get an error-message warning: inline function 'cnVector cnVector::cross(const cnVector&) const' used but never defined.
Copying the implementation into main.cpp works.
Can you explain to me why I can construct a cnVector instance but
the implementation of other methods are not recognized ?
Move your inline functions to your header file. Inline functions need their entire definitions in the header files because of how they integrate with the rest of your code. The compiler will (maybe) attempt to insert the code at all locations where the function is called, so it needs to be visible in the header file similar to how templates need to be entirely present in the header file.