Inter-connected classes

Started by
9 comments, last by Ezbez 16 years, 2 months ago
Hola. I have two classes vec2 and vec3 and each have a function ToVec3 and ToVec2 respectively. I have: Math.h

#ifndef MATH_H
#define MATH_H
#define MATH_TYPE float
class vec3;
class mat4;
class mat3;
class vec2;

#define PI 3.1415926535897932384626433832795
#include "vec3.h"
#include "vec2.h"
#include "mat3.h"
#include "mat4.h"
#endif

But when I try to compile I get:

1>c:\users\xxxx\documents\visual studio 2008\projects\firecube\vec3.h(79) : error C2027: use of undefined type 'FireCube::vec2'
1>        c:\users\xxxx\documents\visual studio 2008\projects\firecube\math.h(7) : see declaration of 'FireCube::vec2'
1>c:\users\xxxx\documents\visual studio 2008\projects\firecube\vec3.h(79) : error C2514: 'FireCube::vec2' : class has no constructors
1>        c:\users\xxxx\documents\visual studio 2008\projects\firecube\math.h(7) : see declaration of 'FireCube::vec2'
Any suggestions on how to make this work? Thanks.
Advertisement
If it's not clear from the error messages what you need to look at, then you should post the code that contains the error messages. Your second error says you have no constructor, so it should be obvious how to fix that.

Take a look at FireCube and if you can't get things working, post the code for it and somebody will be able to give you a better response.
Does vec3.h include vec2.h, or does it define a FireCube::vec2?
It needs to do one of those in order to use a vec2.
You may forward declare a vec2 but all you are able to do is make references/pointers of type vec2 - you cannot instantiate a vec2, call any methods of a vec2, or access any data in a vec2 if it's just a forward declaration.

Look closely at your first error:

1>c:\users\xxxx\documents\visual studio 2008\projects\firecube\vec3.h(79) : error C2027: use of undefined type 'FireCube::vec2'

The second error is probably just a side effect of this first one; I say this because it occurs on the same line, line 79 of vec3.h, which is where you want to take a gander if you want to fix the problem.
Ok, sorry I will try to be more specific:

vec2.h:
class vec2{public:	...	vec2(float nx,float ny) {x=nx;y=ny;}	...	vec3 ToVec3() {return vec3(x,y,0);}	...}

vec3.h:
class vec3{public:	...	vec3(float nx,float ny,float nz) {x=nx;y=ny;z=nz}	...	vec2 ToVec2() {return vec2(x,y);}	...}


When I compile I get an error saying that I use an undefined type vec2 in vec3.h
But as you can see in Math.h before the #include of both vec2.h and vec3.h
I define both classes.
Also each cpp does not include vec2.h or vec3.h directly but rather math.h

SOLVED:
As I was writing this post I solved the problem. I simply had to move the implementation of the functions out of the class definition.
Still I don't get the error messages. The second one about the constructor is ok but the first one about vec2 being undefined, As you can see vec2 was forward declared in Math.h
Quote:Original post by CableGuy
Still I don't get the error messages. The second one about the constructor is ok but the first one about vec2 being undefined, As you can see vec2 was forward declared in Math.h
Declaration and definition are different.

//This is a declarationclass D;  //This is a definitionclass D{public:     void func() {}};

I don't think I'll be able to fully explain it properly, so I'll just reiterate dmatter and say you can create pointers/references to a declared type but you can't use that type (ie: create an instance of it) unless it is first defined. If you need a better description I'll let someone else do it properly and explain how it all works with the compiler and linker.

See here for more information on that error you were getting.
Quote:Original post by CableGuy
When I compile I get an error saying that I use an undefined type vec2 in vec3.h
But as you can see in Math.h before the #include of both vec2.h and vec3.h
I define both classes.
Also each cpp does not include vec2.h or vec3.h directly but rather math.h

It is poor programming practice to rely on that sort of behaviour.
It should be possible to take any single source file and all it's dependancies are visible within that one file; I should not have to guess at other files to look at in order to determine another files dependancies.

Anyway, that idea will only work for vec2 and vec3 will still have problems (as you observed) because of the order of inclusion. If you swapped the #include orders of vec3.h and vec2.h you will find that the error now originates from vec2 instead.

Quote:As you can see vec2 was forward declared in Math.h

As I said above, it's bad style and highly problematic.
Thanks.

dmatter: So what is your suggestion to avoid this "poor programming practice"?
Since my framework has lots of headers, should I include each one that is necessary for a given source file instead of using one master header?
If I explain then it'll be all breezy and confusing, so I'll let Kylotan do it for me. [smile]

As for including a group of similar headers into one header for convenience, it's more 'ok' to do but as the linked article mentions, still problematic.
I would prefer to include every header I need inside each file, with not one redundancy. This is quite common in most reasonably articulate code frameworks, crack open almost any of boosts headers to take a peek and see how many includes some of those have.

The point I was making is that if I look in vec2.h I should be be able to read at the top of the file all its dependancies in the form of forward declarations and includes. The way you have it is that I have to look in math.h to see it's other declarations and includes.
Also, please consider changing the name of math.h to something else, math.h is a C standard library header - ouch.
All the header files don't have any #include statements in them.
The includes are inside the source files...
Original post by CableGuy
class vec2{public:	...	vec2(float nx,float ny) {x=nx;y=ny;}	...	vec3 ToVec3() {return vec3(x,y,0);}	...}


You should be using initialiser lists for constructors as a good programming practice.

example:
class vec2{public:	...	vec2(float nx,float ny) : x(nx), y(ny){}	...	vec3 ToVec3() {return vec3(x,y,0);}	...}


Also naming variables something informative will go a long way if someone were to read your code in the future or if you happen to get delayed and try and revisit it later. (You'd be surprised how fast your memory goes bye bye when dealing with programming)
__________________________________________
Eugene Alfonso
GTP | Twitter | SFML | OS-Dev

This topic is closed to new replies.

Advertisement