I'm learning C++ in a course, using Visual Studio 2013, and I have an issue with include-guards on my main.cpp. I can't use either class or #pragma once (though they work) due to conditions my professor said.
If I only use Coordinates and Line, and I use in main.cpp the #include Line.h (which get code from both Line and Coordinates), this works ok, but when I add Rectangle and Triangle (both have #include "Line.h"), then it throws the "already defined" error LNK2005 several times.
Is there something missing?
This is my code:
Coordinates.h
#ifndef Coordinates
#define Coordinates
//Code declaration. Other headers have similar declaration
struct CoordinatesType { double x, y; } coordinates;
void setCoordinates(double x, double y);
CoordinatesType getCoordinates();
#endif
Coordinates.cpp
#include "Coordinates.h"
//Code implementation
Line.h
#ifndef Line
#define Line
#include "Coordinates.h"
//Code declaration
#endif
Line.cpp
#include "Line.h"
#include <math.h>
//Code implementation
Rectangle.h
#ifndef Rectangle
#define Rectangle
#include "Line.h"
//Code declaration
#endif
Rectangle.cpp
#include "Rectangle.h"
//Code implementation
Triangle.h
#ifndef Triangle
#define Triangle
#include "Line.h"
//Code declaration
#endif
main.cpp
#include "Triangle.h"
#include "Rectangle.h"
int main(){
//Do stuff here.
}
If you need me to add the implementation and declaration codes, let me know, but I feel like it has to do with the include-guard.
EDIT: I'll add code in the Coordinate header so you can get an idea of what I'm doing and to avoid consuming a lot of space in the post. Remember, I can't use class Coordinates{} due to my professor's restriction to not use it.
This error is a linker error, not a compiler error.
Header guards do nothing for the linker.
You have successfully guarded against multiple declarations of things within the same translation unit, but you have not guarded against multiple definitions of things across your whole program.
The way to guard against that is to, well, not do that. There should be no non-inline, non-template definitions of anything in your header if you want to include it into multiple source files.
Here, you declare a type CoordinatesType, and create an object of that type:
struct CoordinatesType { double x, y; } coordinates;
Don't do that! Create an instance of CoordinatesType only in a source file, not in a header. Otherwise, every source file that includes this header (directly or indirectly) will get its own coordinates object and your linker complains about the name collision.
The code should be:
struct CoordinatesType { double x, y; };
Then, either coordinates in the one source file in which you wish to use the object… or extern on its declaration in a header. There are better approaches but I shan't enumerate them all here since this topic has been covered to death on SO already. Furthermore, your C++ book will have an explanation.
But the long and short of it is that this has nothing to do with header guards.
As already pointed out, your problem has nothing to do with include-guards.
Your problem is in this line:
struct CoordinatesType { double x, y; } coordinates;
While the declaration of the struct
struct CoordinatesType { double x, y; };
may appear in multiple .cpp files, as long as it is identical (it is, since you include the same header-file), you also define a variable
CoordinatesType coordinates;
in the same line. Since a definition is only allowed once, your linker complains.
If you really need a global variable of that type (check if you really need one, as it might not be necessary), change your header to a declaration:
struct CoordinatesType { double x, y; };
extern CoordinatesType coordinates;
and use a definition
CoordinatesType coordinates;
in exactly one cpp-file.
Note that the error didn't happen when only including Line and Coordinates, because your include-guards work and you only include the headers in a single .cpp file
Coordinates.h doesn't have any include guard.
When you include it multiple times, it defines Coordinates only once, but the rest of the file is included multiple times.
Put the #endif in the right place.
PS. The identifiers used in the include guards should be something that is never, ever used elsewhere by coincidence. I wouldn't be surprised if someone tried to use a variable named Line or Triangle. And since you #define those, that will lead to very unexpected errors. Use something like #define LineHeader_Included__ .
Related
I am currently working on a project where we have a shared set of headers. Now we want add some private fields without having to put those declarations directly in the shared headers.
Someone brought up the following:
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}
Inside the _private.hpp headers we would then place the private fields for that class. When there are only default datatypes (int, bool, etc) this works fine(ish). But as soon as you put an include inside the _private.hpp file, for example #include everything breaks.
It is giving the following error expected unqualified-id before ‘namespace’ which as I understand is quite logical, since you're trying to define a namespace inside of a class.
Example _private.hpp file
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
Now my question is, is there any way to trick the preprocessor, or somehow get the same results with a different solution?
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#if __has_include("foo_private.hpp")
#include "foo_private.hpp"
#endif
};
}
If that code is including a file that looks like this:
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
Then you end up with this (though in reality, the #includes themselves would resolve to the contents of <string>, etc.):
namespace something {
class Foo {
public:
Foo();
void doFoo();
private:
#ifndef DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#define DUMMY_PRIVATE_TEMPLATE_INCLUDES_FOO_PRIVATE_HPP
#include <string>
int mySecretNumber;
std::string mySecretString;
#endif
};
}
Perhaps that shows your issue? You're including "string" in the middle of your class, but it needs to be included at the global namespace scope of your file.
Instead, include string at the top of the outer header, don't use include guards in the private header, and only put the body of the code you want pasted into your class into that private header. For that reason, you might not call it a ".hpp" file but something else to make it clear it's not a normal header.
Additionally, the __has_include feature seems dubious, because if your private header is missing you probably do not want it to compile to an empty class.
Worse, if you compile some translation unit that finds the header, and then compile another translation unit that does not find the private header, you will end up with two different definitions of your class, violating the One Definition Rule -- which is undefined behavior, no diagnostic required. Really nasty stuff (assuming your builds succeeds at all.)
I'm not a big fan of this kind of hiding, as it will make it hard for editors to properly show your code, to colorize and index your private header, or otherwise work with the code in a normal way. You might consider looking at the PIMPL idiom for hiding the implementation of a class in its .cpp file, so users of the header do not have to see it at all.
I recently came across something that goes against my understanding of includes.
I am creating a dll to hold basic coordinate objects for a personal game engine I'm developing (for fun).
Main dll header file.
#pragma once
#include "sclapi.h"
#include "vector.h"
#include "point.h"
// Other includes and stuff.
// Unimportant for this demonstration.
sclapi.h
#pragma once
#ifdef SCL_EXPORTS
#define SCL_API __declspec(dllexport)
#else
#define SCL_API __declspec(dllimport)
#endif
vector.h
#pragma once
// No includes
/*EDIT*/struct Point;
struct SCL_API Vector {
float x, y;
// Other stuff
explicit operator Point() const;
};
point.h
#pragma once
// No includes
struct SCL_API Point {
int x, y;
// Other stuff
explicit operator Vector() const;
};
My code works perfectly fine; but to my understanding, it shouldn't. A header file should only know what's declared in it (includes being shorthand for pasting in code). None of these objects are declared in the other's header files. [EDITED] point.h should have no knowledge of a Vector struct. Whats more, both even have knowledge of the SCL_API macro. If I comment out individual includes in the main header file, I get the expected compiler errors. What am I missing?
EDIT:
After further testing, I discovered that a declaration of the later objects needs to be in the first header file 'vector.h'; but after, they do not need to be declared again in any other header file. Also, declaring the classes in the main header file does not work. The Point forward declaration must be inside the vector.h file.
When you #include a file, it gets automatically "copypasted" into your source.
Because you included vector.h right before including point.h, the Point class will see it.
However, it's not a good idea to rely on this behavior as the order of includes might change and thus it will not work anymore, so you should #include "vector.h" in your point.h.
Note: The question has already been answered here undirectly
The problem is not include guards : they won't help across different
translation units
Note: I know the solution is to use extern keyword.
I'm new to C++. I have a problem understanding #ifndef in header files. When I do something like this, I get an error saying that the variables game_over and turn are already defined.
/*chess.h*/
#ifndef CHESS
#define CHESS
#include <iostream>
#include "chessboard.h"
using namespace std;
bool game_over;
char turn;
chessboard board;
int main();
#endif
/*bishop.cpp*/
#include "bishop.h"
#include "chess.h"
bishop::bishop(string pos, char color)
{
int x = pos[0] - 97;
int y = pos[1] - 1;
name = "bishop";
this->color = color;
board.add_new(*this);
}
/*chess.cpp*/
#include "chess.h"
int main()
{
...
}
Why are the variables defined twice in here? I thought that first time when chess.h is included, CHESS is defined. So in bishop.cpp, #include "chess.h" will not do anything since the header will skip to #endif from #ifndef CHESS. But it does not work like that obviously. Why am I wrong?
The #ifndef only blocks the code if the symbol is defined within the same translation unit, at a point before the #ifndef. A translation unit is a source file (.cpp) and all the files that are included into it. Since you're compiling two source files, they'll both have a complete include of the .h file.
You already appear to know how to handle the problem of defining global variables in a header file: declare them extern in the header, and put a definition into one of the sources. I would be remiss though if I didn't warn you to avoid globals in the first place, as your programs grow they'll make your life difficult.
Can you please help me to know how I can avoid the error..
Thanks in advance.
file name: point.hh
#ifndef POINT_H
#define POINT_H
class Point{
private:
int x;
int y;
public:
Point();
};
#endif
file name:point.cc
#include "point.hh"
#include <iostream>
using namespace std;
Point::Point()
{
x=0;
y=0;
cout<<"x="<<x;
cout<<"y="<<y;
}
file name: main.cc
#include"point.cc"
int main()
{
Point p; // calls our default constructor
}
You must include the header file, not the source file, in your main.cc file to use the Point class.
That is, replace:
#include"point.cc"
By:
#include"point.hh"
The rationale behind this is that a function definition, unless marked inline, must respect the ODR ("One Definition Rule"). By including the source file in your other source file, you end up having two (identical) definitions of the Point::Point() function in two different translation units.
When the linking process takes place, it sees this two definitions and complains: that is the error you get.
Another cause is the build command, if you have the same .cpp file listed twice you will definitely get this error and it will say that functions you didn't even write have the error.
Might help someone in the future.
I defined a simple class. The definition is in the header file and the implmentation is in the cpp file:
HEADER:
#ifndef POINT_H
#define POINT_H
class Point {
public:
Point(int x, int y);
int getX();
int getY();
private:
int x, y;
};
#endif
CPP
#include Point.h
Point::Point(int x=2, int y=2) {
this->x = x;
this->y = y;
}
int Point::getX() {
return x;
}
int Point::getY() {
return y;
}
This is not compiling and I am not sure why. Also, when I want to instantiate a point
somewhere else, say main.cpp, what do I #include at the top, just Point.h? If so, how does it know to look in Point.cpp?
#include Point.h
You need quotes around Point.h.
Point::Point(int x=2, int y=2)
The default arguments should be in the declaration in the header file, not in the definition in the .cpp file (it will compile as-is, but won't do what you want).
On a stylistic note, it's usually a bad idea to name local variables or arguments the same as member variables: doing so can easily lead to confusion. You can also initialize member variables using an initializer list:
Point::Point(int x_, int y_) : x(x_), y(y_) { }
As your code is currently written, x and y are both constructed, then you assign to them. Using an initializer list eliminates the assignment and just constructs them directly. This doesn't matter for fundamental types like int, but it does matter for class types.
This is not compiling and I am not sure why.
Usually the error message that the compiler issues is helpful. If nothing else, if it isn't helpful to you, it's helpful to those of us trying to help.
Also, when I want to instantiate a point somewhere else, say main.cpp, what do I #include at the top, just Point.h?
Yes.
How does it know to look in Point.cpp?
Each .cpp file that you write gets compiled into a separate object file. Once all the .cpp files are compiled into object files, the object files all get linked together into an excecutable (or a library). The linker figures out where everything is defined.
You are missing quotes in your include
#include "Point.h"
In the file where you want to instantiate a Point you must include Point.h
You should put the argument defaults in the header although without the error message I can't say if this is your problem. Also you should quote your include #include "Point.h"
You defined default values for x and y in the implementation. This can't work. Think a bit how this is supposed to work if the clients of your class only see the header and hence have no idea that they could possibly call Point without default parameters?
The trick is that the implementation is compiled into your application, and calls get resolved using the declaration only (the stuff in the header). For each call, the compiler creates a symbol name and marks the call (for instance, when you call Point::getX, the compiler will insert call which looks like call _getX#Point#). The linker, which comes after the compiler will search for this function. If it's implemented, it will be found and the caller will get "redirected" to the Point::getX() source code.
[Edit] Oh and you need to write #include "Point.h".
What is the error you're getting?
You just include the .h file:
#include "Point.h"
The linker resolves the references to code when it builds the executable.