C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

forward declaration of classes

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
HappyHippy
Guest





PostPosted: Wed Nov 23, 2005 8:40 pm    Post subject: forward declaration of classes Reply with quote



Hi,

I have a question about forward declaration of classes.
First of all, a simple working example, which compiles and works with no
problems.

///file class_a.h:/
#ifndef __CLASS_A_H__
#define __CLASS_A_H__

class classA
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
};

#endif

///file class_b.h:/
#ifndef __CLASS_B_H__
#define __CLASS_B_H__

*class classA; //forward declaration of classA class*

class classB
{
public:
classB(classA *pA): m_pA(pA){}
int getData() const;
void setData(int nData);
private:
classA *m_pA;
};

#endif

///file class_b.cpp:/
#include "class_b.h"
*#include "class_a.h" //here we need to include "class_a.h"*

int classB::getData() const
{
if(m_pA)
return m_pA->getX();

return -1; //let's assume, -1 is an error code
}

void classB::setData(int nData)
{
if(m_pA)
m_pA->setX(nData);
}

It is enough to just put "class classA;" in class_b.h file, since classB
does not have classA members (only pointer-to-classA member), so forward
declaration is enough for compiler, and "#include "class_a.h" is needed
only in implementation file.
That's fine, BUT...

Often you can see a class or a struct declared as:

///file class_a.h:/

#ifndef __CLASS_A_H__
#define __CLASS_A_H__

typedef class
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
} TClassA;

#endif

In this case the previous approach (all other files are the same) does
not work...
MS VC++ 7.1 gives me the following output:
class_a.h(17) : error C2371: 'classA' : redefinition; different basic types
class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2227: left of '->getX' must point to
class/struct/union
class_b.cpp(15) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'
class_b.cpp(15) : error C2227: left of '->setX' must point to
class/struct/union

So, my question is: Is there any way to use forward declaration for
classA to avoid using '#include "class_a.h"' in class_b.h file in the
second case?

Thank you!

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Bob Hairgrove
Guest





PostPosted: Thu Nov 24, 2005 8:03 am    Post subject: Re: forward declaration of classes Reply with quote



On 23 Nov 2005 15:40:09 -0500, HappyHippy <karenman (AT) mail (DOT) ru> wrote:

Quote:
Hi,

I have a question about forward declaration of classes.
First of all, a simple working example, which compiles and works with no
problems.

///file class_a.h:/
#ifndef __CLASS_A_H__
#define __CLASS_A_H__

Do not use identifiers beginning with leading underscores (see section
17.4.3.1.2 of the C++ standard).

[Isn't this in the FAQ somewhere?? If not, it should be.]

Quote:
class classA
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
};

#endif

///file class_b.h:/
#ifndef __CLASS_B_H__
#define __CLASS_B_H__

*class classA; //forward declaration of classA class*

class classB
{
public:
classB(classA *pA): m_pA(pA){}
int getData() const;
void setData(int nData);
private:
classA *m_pA;
};

#endif

///file class_b.cpp:/
#include "class_b.h"
*#include "class_a.h" //here we need to include "class_a.h"*

int classB::getData() const
{
if(m_pA)
return m_pA->getX();

return -1; //let's assume, -1 is an error code
}

void classB::setData(int nData)
{
if(m_pA)
m_pA->setX(nData);
}

It is enough to just put "class classA;" in class_b.h file, since classB
does not have classA members (only pointer-to-classA member), so forward
declaration is enough for compiler, and "#include "class_a.h" is needed
only in implementation file.
That's fine, BUT...

Often you can see a class or a struct declared as:

///file class_a.h:/

#ifndef __CLASS_A_H__
#define __CLASS_A_H__

typedef class
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
} TClassA;

#endif

I never see this in C++ code I work on, only in legacy C code for
struct declarations.

Quote:
In this case the previous approach (all other files are the same) does
not work...
MS VC++ 7.1 gives me the following output:
class_a.h(17) : error C2371: 'classA' : redefinition; different basic types
class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2227: left of '->getX' must point to
class/struct/union
class_b.cpp(15) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'
class_b.cpp(15) : error C2227: left of '->setX' must point to
class/struct/union

So, my question is: Is there any way to use forward declaration for
classA to avoid using '#include "class_a.h"' in class_b.h file in the
second case?

Look at your declaration with the typedef. Maybe you need to use
classA instead of TClassA, or the other way around?

--
Bob Hairgrove
[email]NoSpamPlease (AT) Home (DOT) com[/email]

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Daniel Krügler
Guest





PostPosted: Thu Nov 24, 2005 2:03 pm    Post subject: Re: forward declaration of classes Reply with quote



HappyHippy wrote:

[snip]

Quote:
///file class_b.h:/
#ifndef __CLASS_B_H__
#define __CLASS_B_H__

*class classA; //forward declaration of classA class*

This is invalid C++. But you could write:

class classA;

with the remainder of the header unchanged.

Quote:

class classB
{
public:
classB(classA *pA): m_pA(pA){}
int getData() const;
void setData(int nData);
private:
classA *m_pA;
};

#endif

///file class_b.cpp:/
#include "class_b.h"
*#include "class_a.h" //here we need to include "class_a.h"*

int classB::getData() const
{
if(m_pA)
return m_pA->getX();

return -1; //let's assume, -1 is an error code
}

I would strongly recommend to either assert(m_pA) (or throw an
exception, if pA == 0) in the c'tor of classB accepting a
classA*. Then every member function can be written w/o any further
test with dubious return values, like the one above.

Quote:
void classB::setData(int nData)
{
if(m_pA)
m_pA->setX(nData);
}

Same thing here.

Quote:
It is enough to just put "class classA;" in class_b.h file, since classB
does not have classA members (only pointer-to-classA member), so forward
declaration is enough for compiler, and "#include "class_a.h" is needed
only in implementation file.
That's fine, BUT...

Often you can see a class or a struct declared as:

///file class_a.h:/

#ifndef __CLASS_A_H__
#define __CLASS_A_H__

typedef class
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
} TClassA;

do you mean classA instead of TClassA?

Quote:

#endif

In this case the previous approach (all other files are the same) does
not work...
MS VC++ 7.1 gives me the following output:
class_a.h(17) : error C2371: 'classA' : redefinition; different basic types
class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2227: left of '->getX' must point to
class/struct/union
class_b.cpp(15) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'
class_b.cpp(15) : error C2227: left of '->setX' must point to
class/struct/union

So, my question is: Is there any way to use forward declaration for
classA to avoid using '#include "class_a.h"' in class_b.h file in the
second case?

Strictly speaking: No. Please have a look at the follow-ups of the
thread "How Constructor of typedef class works", where you will find
similar restrictions in the case, where the roles of the
typedef-definition and the class declaration are reversed.

Greetings from Bremen,

Daniel Krügler

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Thu Nov 24, 2005 5:11 pm    Post subject: Re: forward declaration of classes Reply with quote

HappyHippy wrote:
Quote:

Often you can see a class or a struct declared as:

///file class_a.h:/

#ifndef __CLASS_A_H__
#define __CLASS_A_H__

typedef class
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
} TClassA;

#endif

Often? Maybe in C programs or badly written C++ programs. C++ programs
never need to use that idiom and a well-written program should avoid it.

Quote:
So, my question is: Is there any way to use forward declaration for
classA to avoid using '#include "class_a.h"' in class_b.h file in the
second case?

No, and that's one good reason why it's bad C++ programming style to use
that idiom.

Ganesh

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Ulrich Eckhardt
Guest





PostPosted: Thu Nov 24, 2005 5:18 pm    Post subject: Re: forward declaration of classes Reply with quote

HappyHippy wrote:
Quote:
I have a question about forward declaration of classes.

One note here: there is no such thing as a forward declaration. What you
mean is a declaration like e.g. "class A;".

Quote:
#ifndef __CLASS_A_H__
#define __CLASS_A_H__

These are reserved symbols because they contain either two consecutive
underscores or start with an underscore followed by a capital letter.

Quote:
class classA
{
[...]
};

This is called a class definition (as opposed to a declaration), btw.

Quote:
*class classA; //forward declaration of classA class*

I assume the first asterisk here is a typo and you didn't compile with it.


Quote:
That's fine, BUT...

Often you can see a class or a struct declared as:

typedef class
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
} TClassA;

OK. Firstly, let's see how this works: the above defines a class without
giving the class a name, so in other words it is an anonymous class.
However, in the same move it uses a typedef to assign an alias name to this
anonymous class.
Now, for the reasons: in C, names of types and names of structs, enums,
unions all had their own namespace. So, in order to create an object of
type 'struct foo' you really had to write 'struct foo f;' not just 'foo f;'
like in C++. Using typedef, you could alias a struct's name in the types
namespace and from thereon refer to the alias without the struct keyword
before it. This is the reason many people don't even bother assigning a
name in the first place but only create an alias of the anonymous struct.

Quote:
MS VC++ 7.1 gives me the following output:
class_a.h(17) : error C2371: 'classA' : redefinition; different basic
types class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'

MSC gets confused because the name is a 'proper' name in one case and a
typedef in the other case.

Quote:
So, my question is: Is there any way to use forward declaration for
classA to avoid using '#include "class_a.h"' in class_b.h file in the
second case?

You can use
typedef class foo
{...} foo;
i.e. use the same name for the class and the typedef. However, this only
makes sense when it is not a class but a struct/enum/union and needs to be
usable for C, too. Otherwise, don't use this construct.

Lastly, there is an exception which (I think) makes the typedef of an
anonymous struct equivalent to the struct being defined with a proper name,
which is mostly for compatibility between C and C++. I only remember this
vaguely though, maybe someone can step in.

Uli


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
John G Harris
Guest





PostPosted: Fri Nov 25, 2005 6:18 pm    Post subject: Re: forward declaration of classes Reply with quote

In message <ai9g53-fc7.ln1 (AT) satorlaser (DOT) homedns.org>, Ulrich Eckhardt
<eckhardt (AT) satorlaser (DOT) com> writes
Quote:
HappyHippy wrote:
I have a question about forward declaration of classes.

One note here: there is no such thing as a forward declaration. What you
mean is a declaration like e.g. "class A;".
snip


Surely a class declaration whose purpose is forwardly declaring a class
can be called a 'forward declaration' without any risk of confusion.

John
--
John Harris

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze
Guest





PostPosted: Sat Nov 26, 2005 2:37 pm    Post subject: Re: forward declaration of classes Reply with quote

Ulrich Eckhardt wrote:
Quote:
HappyHippy wrote:

One note here: there is no such thing as a forward
declaration. What you mean is a declaration like e.g. "class
A;".

Technically, this defines the class as an incomplete type. I
think it is common usage, however, to refer to this particular
type of definition as a forward declaration.

[...]
Quote:
class classA
{
[...]
};

This is called a class definition (as opposed to a
declaration), btw.

*class classA; //forward declaration of classA class*

I assume the first asterisk here is a typo and you didn't
compile with it.

I think he just added the * to draw attention to the line.

Quote:
That's fine, BUT...

Often you can see a class or a struct declared as:

typedef class
{
public:
int getX() const
{
return m_nX;
}
void setX(int nX)
{
m_nX = nX;
}
private:
int m_nX;
} TClassA;

OK. Firstly, let's see how this works: the above defines a
class without giving the class a name, so in other words it is
an anonymous class. However, in the same move it uses a
typedef to assign an alias name to this anonymous class.

§7.1.3/5: "If the typedef declaration defines an unnamed class
(or enum), the first typedef-name declared by the declaration to
be that class type (or enum type) is used to denote the class
type (or enum type) for linkage purposes only.

It's a hack, for C compatibility, because the above idiom was
frequent in C. (The above works in C because C uses structural
type matching, at least between compilation units. C++ uses
name equivalence.)

Quote:
MS VC++ 7.1 gives me the following output:
class_a.h(17) : error C2371: 'classA' : redefinition; different basic
types class_b.h(1) : see declaration of 'classA'
class_b.cpp(7) : error C2027: use of undefined type 'classA'
class_b.h(1) : see declaration of 'classA'

MSC gets confused because the name is a 'proper' name in one
case and a typedef in the other case.

I don't know what the current situation is, but in the past,
VC++ has had problems in this area. Things like a forward
declaration "class A ;" not matching a definition which started
"struct A { ...". So this could easily be simply a bug in the
compiler.

On the other hand, I'm not really too sure about the exact
meaning of "for linkage purposes only". I would have
interpreted it to mean that the following was legal:

class A ;

typedef struct
{
int x ;
int y ;
} A ;

but the two compilers available to me (Sun CC and g++) both
disagree, although the error message from g++ is:
equiv.cc:8: error: conflicting declaration 'typedef struct A A'
equiv.cc:2: error: 'struct A' has a previous declaration as `struct
A'
which suggests something wrong interally -- it is, at any rate
treating the anonymous structure as having the name A.

It may be that the compilers are refusing the typedef for A
because there is already a symbol A defined. But I don't really
see how this is different from something like:

struct A { int x ; int y ; } ;
int A ;

which both compilers accept without complaining. On the other
hand, the distinction makes some sense: the rule is for C
compatibility, the above is legal in C, where as the example
with the typedef (even replacing class with struct in the
forward declaration) isn't.

Quote:
So, my question is: Is there any way to use forward
declaration for classA to avoid using '#include "class_a.h"'
in class_b.h file in the second case?

You can use
typedef class foo
{...} foo;

i.e. use the same name for the class and the typedef. However,
this only makes sense when it is not a class but a
struct/enum/union and needs to be usable for C, too.
Otherwise, don't use this construct.

Most of the time that I've had problems with these sort of
things, it has involved headers that I couldn't modify.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Dan McLeran
Guest





PostPosted: Sat Nov 26, 2005 2:52 pm    Post subject: Re: forward declaration of classes Reply with quote

Quote:
Often? Maybe in C programs or badly written C++ programs. C++ programs
never need to use that idiom and a well-written program should avoid it.

Are you saying that forward-declaration is a bad practice? If so, I
think Andrei Alexandrescu and Herb Sutter would disagree with you. This
technique is one of the recommended practices from their book, C++
Coding Standards ([url]http://www.gotw.ca/publications/c++cs.htm)[/url].

I can't remember which one, because I left my copy at work.


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
James Kanze
Guest





PostPosted: Sun Nov 27, 2005 3:58 am    Post subject: Re: forward declaration of classes Reply with quote

Dan McLeran wrote:
Quote:
Often? Maybe in C programs or badly written C++ programs. C++
programs never need to use that idiom and a well-written
program should avoid it.

Are you saying that forward-declaration is a bad practice?

No. He's saying that you shouldn't write:

typedef class { ... } C ;

Just

class C { ... } ;

does the job nicely.

--
James Kanze mailto: [email]james.kanze (AT) free (DOT) fr[/email]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Alberto Ganesh Barbati
Guest





PostPosted: Sun Nov 27, 2005 4:01 am    Post subject: Re: forward declaration of classes Reply with quote

Dan McLeran wrote:
Quote:
Often? Maybe in C programs or badly written C++ programs. C++ programs
never need to use that idiom and a well-written program should avoid it.

Are you saying that forward-declaration is a bad practice?

Of course not! I was referring only to this idiom reported in the OP and
clearly quoted in my post:

typedef class /* NO NAME HERE */
{
/* definition here */
} TClassA;

which makes little sense in C++. One of the reason why it makes so
little sense is that you can't forward declare such a class. (let alone
the fact that you can't declare neither a constructor nor a destructor).

Ganesh

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.