Reputation: 3437
I have two classes, Mesh and MeshList. I want MeshList to have a function that can change the private members of Mesh. But it won't compile and I don't know why. Here's my code.
Mesh.h
#ifndef _MESH_H
#define _MESH_H
#include "MeshList.h"
#include <iostream>
class Mesh
{
private:
unsigned int vboHandle_;
friend void MeshList::UpdateVBOHandle();
public:
inline void Out() {std::cout << vboHandle_;}
};
#endif
Mesh.cpp
#include "Mesh.h"
MeshList.h
#ifndef _MESH_LIST_H
#define _MESH_LIST_H
#include "Mesh.h"
class MeshList
{
public:
Mesh *mesh; //Line 11 Error
void UpdateVBOHandle();
};
#endif
MeshList.cpp
#include "MeshList.h"
void MeshList::UpdateVBOHandle()
{
*mesh->vboHandle_ = 4;
}
I get these errors:
MeshList.h (Line 11)
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
mesh.h(11) : error C2653: 'MeshList' : is not a class or namespace name
Upvotes: 32
Views: 1054
Reputation: 4247
Cyclic dependencies are explained in the other answers...
Here comes the solution:
In MeshList.h
:
#include "Mesh.h"
with the forward declaration class Mesh;
(You don't need the include here, because you only declare a pointer to a Mesh)In MeshList.cpp
:
#include "Mesh.h"
to your includes (you need the declaration, because you use the Mesh)The last compile error, you mentioned is another problem:
*mesh->vboHandle_ = 4;
mesh
is a pointer. Your code selects the member vboHandle_
and tries to dereference it (which fails). I suppose you mean:
mesh->vboHandle_ = 4; // <-- no leading asterisk
Upvotes: 7
Reputation: 299880
The problem: Cyclic dependencies in your includes. The error message is less than ideal, unfortunately.
The solution: If you befriend the whole class, instead of a single function, then you can use a forward declaration of the class to break the cycle.
// Mesh.h
#ifndef _MESH_H
#define _MESH_H
#include <iostream>
class MeshList;
class Mesh
{
private:
unsigned int vboHandle_;
friend class MeshList;
public:
inline void Out() {std::cout << vboHandle_;}
};
#endif
Some (subjective) guidelines:
Include stuff in reverse order of your ability to change it if it breaks, that is: STL first, 3rd party headers second, your own middleware stack third, the current project includes fourth and the current library includes fifth. This way, if there is a conflict, hopefully the error will point to a header of yours.
Put the public
stuff before the private
stuff in a class. Clients of the class are only concerned with the public interface, no need to have them wade through all the dirty implementation details before they can get to it.
Upvotes: 4
Reputation: 9523
It's because you've #include "MeshList.h"
in the file Mesh.h
, so the file MeshList.h
will be compiled first, and the class Mesh
is not yet declared. For that the compiler will think that Mesh
in the error line is a variable name that has not got a type before it, hence the error.
This is an example of making a friend
member function:
#include <iostream>
class foo;
class bar
{
public:
void barfunc(foo &f);
};
class foo
{
private:
friend void bar::barfunc(foo &f);
int i;
public:
foo()
{
i = 0;
}
void printi()
{
std::cout << i << '\n';
}
};
void bar::barfunc(foo &f)
{
f.i = 5;
}
int main()
{
foo f;
bar b;
b.barfunc(f);
f.printi();
return 0;
}
Upvotes: 6
Reputation: 19981
When you compile Mesh.cpp
, it includes Mesh.h
, which includes MeshList.h
, which starts to include Mesh.h
but stops early because _MESH_H
is now defined. Then (back in MeshList.h
) there's a reference to Mesh
-- but that hasn't been declared yet. Hence, e.g., your C2143 error.
Upvotes: 9