Apologies if you have seen this question before however it has yet to be answered, essentially in my code I have two structs, defined in separate headers and used globally throughout the project. I simply wish to use both structs (which again, are defined in two separate headers) in other cpp files than just the ones that the header file belongs to.
Here is some sample code which I have tested:
class1.h
#include "class2.h"
#include <vector>
#include <string>
struct trans1{
string name;
};
class class1 {
private:
vector <trans2> t2;
public:
class1();
};
class2.h
#include "class1.h"
#include <vector>
#include <string>
struct trans2{
string type;
};
class class2{
private:
vector <trans1> t1;
public:
class2();
};
errorlog:
In file included from class1.h:3:0,
from class1.cpp:1:
class2.h:21:13: error: 'trans1' was not declared in this scope
vector <trans1> t1;
^
class2.h:21:19: error: template argument 1 is invalid
vector <trans1> t1;
^
class2.h:21:19: error: template argument 2 is invalid
I understand that this is ridiculous code in a real world application however this is the simplest way I could demonstrate.
It is worth noting that if I simply comment out the declaration of vector t1 or t2 under 'private:' the code compiles without fail. It is just the fact I am using a second struct.
Any help anyone? Thanks.
Simply forward-declare the classes that will be used. Put all implementation code into a cpp file, not inline in the header.
Make the vector private. This way no file that includes the header can force code generation against an incomplete class.
you can try to forward declare trans1 in class2.h and trans2 in class1.h like this:
class2.h :
// includes
struct trans1;
// rest of your code
the same thing (but with trans2) in class1.h
Don't forget to add Include guards in your code!
edit: and yes, you need to change your vectors to store pointers, otherwise it won't link
You need to put the "trans" structs in their own header file(s) and include them in your class header files.
You could forward declare them, but this would require changing your vector to use pointers. (In that case I would recommend std::vector<std::unique_ptr<trans>>). This could be appropriate if your structs are big and complex.
The main advantage of the forward-declaration approach is to reduce compile times. However if the structs are really so simple as in your example, I wouldn't bother with the extra overhead of using pointers here.
If You were to do this in single .cpp file, the solution would be trivial:
struct trans1 { ... };
struct trans2 { ... };
class class1 { ... };
class class2 { .... };
Now you just need to rearrange the code to get this result in every translation unit. (the order of classes/structs in the file is important)
Related
I have three classes.
first class:
#ifndef C_LINKED_LIST_H
#define C_LINKED_LIST_H
class CLinkedList {
private:
//removed code for brevity
public:
// removed code for brevity
};
#endif
second class:
#ifndef C_SSF_FOLDER_CONTAINER_H
#define C_SSF_FOLDER_CONTAINER_H
#include "C_SSF_Folder.h"
#include "CLinkedList.h"
class C_SSF_Folder_Container {
private:
// removed code for brevity
public:
int Add_Folder(C_SSF_Folder *_pcl_SSF_Folder);
C_SSF_Folder *Get_Folder(int _i_Index);
C_SSF_Folder *Get_Folder(char *_pch_Name);
//^-----errors
};
#endif C_SSF_FOLDER_CONTAINER_H
my third class
#ifndef C_SSF_FOLDER_H
#define C_SSF_FOLDER_H
#include <windows.h>
#include <fstream>
#include "C_SSF_Folder_Container.h"
using namespace std;
class C_SSF_Folder {
public:
private:
C_SSF_Folder_Container cl_SSFFC_Folder_Container;
public:
};
#endif
my third class C_SSF_Folder.
I am including "C_SSF_Folder_Container.h"
and declaring a C_SSF_Folder_Container container.
Before declaring the variable it compiles fine. After I declare it
I get syntax errors in my C_SSF_Folder_Container
Severity Code Description Project File Line Suppression State
Error C2061 syntax error: identifier 'C_SSF_Folder' CSSFileSystem\projects\cssfilesystem\cssfilesystem\c_ssf_folder_container.h 16
Error C2061 syntax error: identifier 'C_SSF_Folder' CSSFileSystem \projects\cssfilesystem\cssfilesystem\c_ssf_folder_container.h 19
As I myself look into it I think there is a problem because my C_SSF_Folder is including C_SSF_Folder_Container.
and C_SSF_Folder_Container is including C_SSF_Folder
but the defines should take care of it? Other than that I have no clue what's the problem.
Everything is typed correctly.
You've got a circular #include -- C_SSF_Folder_Container.h #includes C_SSF_Folder.h and C_SSF_Folder.h #includes C_SSF_Folder_Container.h.
This would cause an infinite regress (and a compiler crash) except that you've got the #ifndef/#define guards at the top of your files (as you should); and because of them, instead what you get is that one of those two .h files can't see the other one, and that's why you get those errors.
The only way to fix the problem is to break the circle by deleting one of the two #includes that comprise it. I suggest deleting the #include "C_SSF_Folder.h" from C_SSF_Folder_Container.h and using a forward declaration (e.g. class C_SSF_Folder; instead.
C_SSF_Folder.h and C_SSD_Folder_Container.h are including each other(Circular Dependency).
When the compiler compiles C_SSF_Folder_Container object, it needs to create a C_SSF_Folder object as its field, however, the compiler needs to know the size of C_SSF_Folder object, so it reaches C_SSF_Folder object and tries to construct it. Here is the problem, when the compiler is constructing C_SSF_Folder object, the object has a C_SSF_Folder_Container object as its field, which is a typical chicken and egg question, both files depends on each other in order to compile.
So the correct way to do it is to use a forward declaration to break the circular dependency(including each other).
In your C_SSF_Folder.h, make a forward declaration of C_SSF_Folder_Container.
#include <windows.h>
#include <fstream>
using namespace std;
class C_SSF_Folder_Container;
class C_SSF_Folder {
public:
private:
C_SSF_Folder_Container cl_SSFFC_Folder_Container;
public:
};
#endif
Finally, include C_SSF_Folder_Container.h in your C_SSF_Folder.cpp.
You can also learn more in the following links:
Circular Dependency (Wiki):
https://en.wikipedia.org/wiki/Circular_dependency
Forward Declaration by Scott Langham
What are forward declarations in C++?
I can't solve this circular dependency problem; always getting this error:
"invalid use of incomplete type struct GemsGame"
I don't know why the compiler doesn't know the declaration of GemsGame even if I included gemsgame.h
Both classes depend on each other (GemsGame store a vector of GemElements, and GemElements need to access this same vector)
Here is partial code of GEMELEMENT.H:
#ifndef GEMELEMENT_H_INCLUDED
#define GEMELEMENT_H_INCLUDED
#include "GemsGame.h"
class GemsGame;
class GemElement {
private:
GemsGame* _gemsGame;
public:
GemElement{
_gemsGame = application.getCurrentGame();
_gemsGame->getGemsVector();
}
};
#endif // GEMELEMENT_H_INCLUDED
...and of GEMSGAME.H:
#ifndef GEMSGAME_H_INCLUDED
#define GEMSGAME_H_INCLUDED
#include "GemElement.h"
class GemsGame {
private:
vector< vector<GemElement*> > _gemsVector;
public:
GemsGame() {
...
}
vector< vector<GemElement*> > getGemsVector() {
return _gemsVector;
}
}
#endif // GEMSGAME_H_INCLUDED
Remove the #include directives, you already have the classes forward declared.
If your class A needs, in its definition, to know something about the particulars of class B, then you need to include class B's header. If class A only needs to know that class B exists, such as when class A only holds a pointer to class B instances, then it's enough to forward-declare, and in that case an #include is not needed.
If you deference the pointer and the function is inline you will need the full type. If you create a cpp file for the implementation you can avoid the circular dependecy (since neither of the class will need to include each others .h in their headers)
Something like this:
your header:
#ifndef GEMELEMENT_H_INCLUDED
#define GEMELEMENT_H_INCLUDED
class GemsGame;
class GemElement {
private:
GemsGame* _gemsGame;
public:
GemElement();
};
#endif // GEMELEMENT_H_INCLUDED
your cpp:
#include "GenGame.h"
GenElement::GenElement()
{
_gemsGame = application.getCurrentGame();
_gemsGame->getGemsVector();
}
Two ways out:
Keep the dependent classes in the same H-file
Turn dependency into abstract interfaces: GemElement implementing IGemElement and expecting for IGemsGame, and GemsGame implementing IGemsGame and containing a vector of IGemElement pointers.
Look at the top answer of this topic: When can I use a forward declaration?
He really explains everything you need to know about forward declarations and what you can and cannot do with classes that you forward declare.
It looks like you are using a forward declaration of a class and then trying to declare it as a member of a different class. This fails because using a forward declaration makes it an incomplete type.
I'm trying to refactor my code so that I use forward declarations instead of including lots of headers. I'm new to this and have a question regarding boost::shared_ptr.
Say I have the following interface:
#ifndef I_STARTER_H_
#define I_STARTER_H_
#include <boost/shared_ptr.hpp>
class IStarter
{
public:
virtual ~IStarter() {};
virtual operator()() = 0;
};
typedef boost::shared_ptr<IStarter> IStarterPtr;
#endif
I then have a function in another class which takes an IStarterPtr object as argument, say:
virtual void addStarter(IStarterPtr starter)
{
_starter = starter;
}
...
IStarterPtr _starter;
how do I forward declare IStarterPtr without including IStarter.h?
I'm using C++98 if that is of relevance.
Shared pointers work with forward declared types as long as you dont call * or -> on them so it should work to simply write :-
class IStarter;
typedef boost::shared_ptr<IStarter> IStarterPtr;
You need to include <boost/shared_ptr.hpp> of course
Though it would add a header file, you could put that in a separate header file :
#include <boost/shared_ptr.hpp>
class IStarter;
typedef boost::shared_ptr<IStarter> IStarterPtr;
and then include it both in IStarter.h and in your other header, avoiding code duplication (though it's quite small in this case).
There might be better solutions though.
You can't forward declare typedefs in C++98 so what I usually do in this case is pull out the typedefs I need an put them into a types.h file, or something similar. That way the common type code is still separated from the definition of the class itself.
There is a way but you need to include the boost header in your file :
#include <boost/shared_ptr.hpp>
class IStarter;
typedef boost::shared_ptr<IStarter> IStarterPtr;
// ...
virtual void addStarter(IStarterPtr starter)
{
_starter = starter;
}
// ...
IStarterPtr _starter;
I am programming on linux using g++ and I often encounter the problem that I need to use a class or data type in a header file which I define later, either at a later point in the header or in another header file.
For instance look at this header file:
class example
{
mydatatype blabla;
};
struct mydatatype
{
int blablainteger;
char blablachar;
};
This will give error because mydatatype is used before its defined
so usually I change it like this:
struct mydatatype; // <-- class prototype
class example
{
mydatatype *blabla; // <-- now a pointer to the data type
// I will allocate the data during runtime with the new operator
};
struct mydatatype
{
int blablainteger;
char blablachar;
};
Now it works. I could often just put the definition above, or include the header which is needed, but I don't want to include headers in a header or juggle with the definition order, it always gets messy.
The solution I showed usually works, but now I have encountered a new phenomenon. This time the datatype is not a class but a typedef, I cant use prototypes for a typedef and I don't want to use the actual datatype which the typedef incorporates.. it's messy too.
Is there any solution to this?
Firstly, the solution you've thought of (prototype and pointer), is unneeded, and slower than just implementing it without the pointer.
The "proper" solution for this, would be creating seperate headers for each type, and then include them in your other header. That way it will always be defined! You can even make them so that they include eachother.
However, if you've ever opened a .h file provided by g++, you've most likely seen this at the start of the header:
#ifndef SOMETHING_H
#define SOMETHING_H
// Code
#endif /* SOMETHING_H */
This is to solve the issue of types redefining themselves.
If they weren't there, and you included the header file multiple times, the types would be redefined, and an error would be thrown. This makes it so that the types are always present, but never included twice.
I hope that helps!
Place each class/type in it's own header file, and then include the relevant header file in other headers where you need it. Use an inclusion guard in each header e.g.:
// SomeHeaderFile.h
#ifndef SOME_HEADER_FILE_H
#define SOME_HEADER_FILE_H
// code
#endif
I disagree that this is messy - it allows you have an organised structure to you project, it allows each class to operate independently of others and without worrying about order, and it's a good idea to place each class in it's own file anyway.
You could just define the class inside the other class like
template<class T>
class vertex {
private:
class edge {
public:
vertex<T> *to;
double weight;
edge() {
weight = INFINITY;
to = NULL;
};
} *paths;
T data;
unsigned nof_paths;
public:
vertex(T val) {
data = val;
paths = NULL;
nof_paths = 0;
}
void addPathTo(vertex<T>*&);
edge* getAllPaths() {
return paths;
};
};
Obviously this works for small classes... if your class is ENORMOUS you'll be better using separate header files like the other guys said.
I'm working on a class assignment that started small, so I had it all in one file. Now it's gotten bigger and I'm trying to separately compile main, functions, and classes (so all the classes are together in one .h and one .cpp) I have one class B, which is the parent of a lot of others and comes first in the file. One of its data members isn't working now that I'm using separate compilation, which is causing dozens of errors.
In .h
class A;
class B {
public:
B (){}
A* myptr;
void whatever();
vector<A*> myAs; //this one is the problem
};
In .cpp
void B::whatever() {
vector<A*> newvector; //no problem!
myptr = &something; //no problem!
for (vector<A*>::iterator iter = myAs.begin(); iter != myAs.end(); ++iter) {
//error!
}
}
I get errors: either "myAs was not declared in this scope" or "class B has no member myAs."
I've included < vector >, forward-declared class A as you see above, and I definitely remembered to include the .h at the top of the .cpp! Is there something about vectors or classes and separate compilation that I don't understand? This is in Xcode, BTW.
It's not just vector. It's std::vector because it is within the namespace called std. That's why the compiler moans. It doesn't know what vector<A*> means. Say std::vector<A*> instead.
Do not add using namespace std; now into the header because of this. It may be OK for the assignment to put it into the .cpp file to save typing if you wish. But it's a really bad idea to put such a line into a header: Because you don't know which files will need your header in future. The situation can quickly get out of hand as the amount of files including your header grows with time. The header should therefor include only the names and headers that it really needs so that it causes as little name conflicts as possible - whereas that using namespace std; line would make all names of std visible directly.