473,396 Members | 1,924 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Avoid including header file by declaring class. But what for typedef???

Hello.

If I have the following classes:

class B {};
typedef B tB;

if A is:

class A
{
void f(B* pB) {}
};

in the header where A is defined, I can write
class B;
to avoid including the header file declaring B.

But what for typedef:

if A is:

class A
{
void f(tB* pB) {}
};

if I write
class tB;
in A.h, I have the follwing compiler error:
error C2371: 'tB' : redefinition; different basic types, because a
typedef is not a class.

I tried several syntax, but finally, is it possible to declare a
typedef like we do for a class?

Thanks for help.
Aug 20 '08 #1
8 4544
On Aug 20, 9:50 am, nguillot <nicolas.guil...@gmail.comwrote:
Hello.

If I have the following classes:

class B {};
typedef B tB;

if A is:

class A
{
void f(B* pB) {}

};

in the header where A is defined, I can write
class B;
to avoid including the header file declaring B.
No, you definitely want to include that header.
Thats what include guards are for.
>
But what for typedef:

if A is:

class A
{
void f(tB* pB) {}

};

if I write
class tB;
in A.h, I have the follwing compiler error:
error C2371: 'tB' : redefinition; different basic types, because a
typedef is not a class.

I tried several syntax, but finally, is it possible to declare a
typedef like we do for a class?

Thanks for help.

First off, use a const reference or a reference instead of a pointer.
Typedef's are not neccessarily usefull.
If you don't show compileable code, we can only guess at your problem.
Guessing is bad, very bad.
Use include guards, as follows:

// A.h
#ifndef A_H_
#define A_H_

#include <iostream>
#include "B.h"

class A
{
public:
void f(const tB& rb)
{
std::cout << "n = ";
std::cout << rb.get();
std::cout << std::endl;
}
};

#endif

// B.h
#ifndef B_H_
#define B_H_

class B
{
int n;
public:
B() : n(99) { }
int get() const { return n; }
};

typedef B tB; // ugly

#endif

// test.cpp
#include "A.h"

int main()
{
A a;
tB b;
a.f( b );
}
Aug 20 '08 #2
On Aug 20, 10:50*pm, nguillot <nicolas.guil...@gmail.comwrote:
[snip] I can write
class B;
to avoid including the header file declaring B.
You can but you shouldn't, despite lots of generally respected authors
recommending it.

If the developer of the header declaring B thinks including the header
imposes (or may one day impose) a significant performance penalty,
they should provide a forward-declaration header (e.g. <iosfwd>
instead of <iostream>). If they haven't provided such a header, and
you can't talk them into doing so, and you're working on a non-trivial
project with many source files using their header, then you can create
and maintain a single forward-declaration header yourself. Still
painful, but at least centralised.

Declaring things that the B-developer is quite entitled to change at
any time (e.g. from a class to a typedef to a template instantiation)
is as bad as the olden-days habit of not using headers, and having
extern declarations for the extra-translation-unit functions you plan
to call....

To make the most of your build tools (e.g. make), you have to work in
with their logic about recompilation, not fight it with hacks.
Changes with compatible usage should trigger a rebuild.

Cheers,
Tony
Aug 20 '08 #3
On Aug 20, 6:50 am, nguillot <nicolas.guil...@gmail.comwrote:
>
If I have the following classes:

class B {};
typedef B tB;

if A is:

class A
{
void f(B* pB) {}
};

in the header where A is defined, I can write
class B;
to avoid including the header file declaring B.

But what for typedef:

if A is:

class A
{
void f(tB* pB) {}
};

if I write
class tB;
in A.h, I have the follwing compiler error:
error C2371: 'tB' : redefinition; different basic types, because a
typedef is not a class.

I tried several syntax, but finally, is it possible to declare a
typedef like we do for a class?
Yes, by redeclaring the tB typedef in A.h:

// A.h

class B;

typedef B tB;

Greg
Aug 20 '08 #4
On Wed, 20 Aug 2008 12:48:03 -0700 (PDT), to***********@yahoo.co.uk <to***********@yahoo.co.ukwrote:
On Aug 20, 10:50*pm, nguillot <nicolas.guil...@gmail.comwrote:
>[snip] I can write
class B;
to avoid including the header file declaring B.

You can but you shouldn't, despite lots of generally respected authors
recommending it.
....
Declaring things that the B-developer is quite entitled to change at
any time (e.g. from a class to a typedef to a template instantiation)
is as bad as the olden-days habit of not using headers, and having
extern declarations for the extra-translation-unit functions you plan
to call....
Unlike that old pain, a "class B;" in my code cannot silently cause my
program to stop working, can it?
To make the most of your build tools (e.g. make), you have to work in
with their logic about recompilation, not fight it with hacks.
Changes with compatible usage should trigger a rebuild.
I take it that is your main argument against forward declarations.

I disagree, at least in the case where I am the author of class B and
can change both B and the code which uses it whenever needed.
Bringing down compilation times is worth a lot, in my opinion. I also
prefer my code seeing as few names as possible, even if everything is
in namespaces and there are no macros with too generic names.

To answer the original question a bit: I think the problem he sees
with typedefs is a reason many people prefer not to typedef classes.

/Jorgen

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.se R'lyeh wgah'nagl fhtagn!
Aug 21 '08 #5
On Aug 20, 9:50*am, nguillot <nicolas.guil...@gmail.comwrote:
Hello.

If I have the following classes:

class B {};
typedef B tB;

if A is:

class A
{
* * void f(B* pB) {}

};

in the header where A is defined, I can write
class B;
to avoid including the header file declaring B.

But what for typedef:

if A is:

class A
{
* * void f(tB* pB) {}

};

if I write
class tB;
in A.h, I have the follwing compiler error:
error C2371: 'tB' : redefinition; different basic types, because a
typedef is not a class.

I tried several syntax, but finally, is it possible to declare a
typedef like we do for a class?
Well... You say theerror is in A.h. But, I'md doubting it.
I'm thinking the error is actually in some .CPP file that
includes the A.h header.

This would seem to indicate that some .CPP file includes both
A.h and B.h.

As others have said, you want to resist this scheme.
If you absolutely need it, can't do without it, then...

So what to do about that? Well, clearly what you need is
some kind of include guard. Getting down to the level of
individual typedefs is, maybe, a little finicky.

But as somebody suggested, you want a Bfwd, or forward
defn header. And it gets its own include guards. If you
have control of both B.h and A.h then you can have B.h
include Bfwd.h for the typedef, and that way make sure
it is identical in both B.h and A.h.

And that gets you past the gnarly possible things that
might happen if the class B changes.
Socks
Aug 21 '08 #6
Thanks for all your answers.

To answer to some comments:

I don't see why typedef B tB; is ugly.
If B is std::map<std::string, std::.....the typedef is worth.
With the typedef I can write tB::iterator, instead of
std::map<std::string, std::.....>::iterator.
And it factorizes the code.

About providing compileable code, so you only can guess... Do you
really think it's a problem.
I guess the problem was explain (and the problem is not about pointer
or reference), it's about including header or forwarding declarations;
and how to forward the declaration of a typedef. Not more about
protecting header with the guard #ifdef...
But sorry if my question was not clear.

My main question was indeed (but I learned the correct vocabulary by
reading your answers):
how to forward declare a typedef.

About using headers instead of forward declaration, I guess it's a
real debate. Good authors defend one way or the other.

For my problem, I would need this forward declaration to decrease the
compilation time (really decrease!).
A.h as B.h are my code, I have access to it.

So because it's really worth to decrease compilation time, the
solution would to provide a forward header... I'll try that way.

Thanks a lot for your answers.
Aug 21 '08 #7
On Aug 22, 1:30 am, Jorgen Grahn <grahn+n...@snipabacken.sewrote:
Unlike [embedded extern fn declarations], a "class B;" in my code
cannot silently cause my program to stop working, can it?
Depends who you are in the software system, what you call silently and
working, and what expectations and responsibilities you feel different
developers involved can have of and to each other.

As a library developer defining a class X in a header, I would argue
that you are entitled to replace it with "template <typename Tclass
XT {...}; typedef XT<intX;", as well-written client code that
includes your header will seamlessly recompile and work. This is
standard practice when evolving code is generalised to arbitrary
types.

But - silently from the perspective of the library developer who
doesn't necessarily know about all client usage or trigger client app
recompilation - poorly-written client code hard-coding "class X;" will
break. Scenario: Some production issue requires a urgent bug fix and
instead the app developer finds unrelated parts of their app aren't
compiling any more and must be fixed simultaneously, delaying
deployment of the fix. If the library developer considers their
clients as part of their overall "system" (a responsible attitude and
generally expected in corporate life at least), then yes their change
broke their system. But they're not really to blame....

Can it be worse? Probably. Thinking about all the combinations of
layers of objects, headers, static vs load-time vs run-time binding
etc. does my head in and I'd need a better reason for suffering that
than this thread.

About the best that can be said is that at least some of these issues
differ from extern function abuses, where the consequences are more
consistently in the SIGSEGV category ;-).
To make the most of your build tools (e.g. make), you have to work in
with their logic about recompilation, not fight it with hacks.
Changes with compatible usage should trigger a rebuild.

I take it that is your main argument against forward declarations.

I disagree, at least in the case where I am the author of class B and
can change both B and the code which uses it whenever needed.
Bringing down compilation times is worth a lot, in my opinion. I also
prefer my code seeing as few names as possible, even if everything is
in namespaces and there are no macros with too generic names.
Forward declaration headers - maintained by the downstream library -
are the only proper way to handle this. If a header pulls in myriad
other headers AND has many independent parts then it's a strong
candidate for separation into multiple headers / forward-declaration
pairs, with the original header including the parts. This way
upstream clients can select those parts that are useful without the
full burden of including extra headers. pImpl / envelope-letter
idioms help. If managed maturely, the compilation times can almost
always be kept thoroughly under control and don't begin to justify the
complications of the "class X;" hack.

Tony
Aug 22 '08 #8
(A very late response)

On Fri, 22 Aug 2008 01:57:26 -0700 (PDT), to***********@yahoo.co.uk <to***********@yahoo.co.ukwrote:
On Aug 22, 1:30 am, Jorgen Grahn <grahn+n...@snipabacken.sewrote:
>Unlike [embedded extern fn declarations], a "class B;" in my code
cannot silently cause my program to stop working, can it?

Depends who you are in the software system, what you call silently and
working, and what expectations and responsibilities you feel different
developers involved can have of and to each other.

As a library developer defining a class X in a header [...]
You are probably right about the library case, but I do not think it
is so common that it should dictate general practice.

My basic assumption was that I was *not* a library developer, i.e.
that I personally link the final executable, or a close co-worker
does. Or put more in configuration management terms, that we deliver
executables, and noone delivers inputs to us, except well-tested and
stable 3rd-party libraries.

In that scenario, I can save a lot of work and uncertainty by making
assumptions about the code (and I can refactor any part of it until
the assumptions hold).

And I also believe lots of bad code has been written because it was
needlessly written as if it was a library. I *still* see classes
where a lot of work is spent on unused features: "virtual" for classes
which noone inherits from, copy constructors and operator= for classes
which noone copies, function arguments with default values which noone
ever provides ...

/Jorgen

--
// Jorgen Grahn <grahn@ Ph'nglui mglw'nafh Cthulhu
\X/ snipabacken.se R'lyeh wgah'nagl fhtagn!
Sep 8 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

11
by: Steven T. Hatton | last post by:
In the past there have been lengthy discussiions regarding the role of header files in C++. People have been very adamat about header files serving as in interface to the implementation. I do...
1
by: Scott Yost | last post by:
I have a managed class A which I import via a DLL. public __gc class A { public B otherClass; } And another class C which is just in a CPP file - not in the DLL. #include <b.h> class C
0
by: Lokkju | last post by:
I am pretty much lost here - I am trying to create a managed c++ wrapper for this dll, so that I can use it from c#/vb.net, however, it does not conform to any standard style of coding I have seen....
3
by: AK | last post by:
I'm using a .NET Windows Forms Applications project. I'm using LoadLibrary & GetProcAddress to use a DLL function. This is all done in the main cpp file. I would like to use this DLL function in a...
11
by: Gary Wessle | last post by:
Hi is it right to have a line like #include <path/to/header.hfor a library on my system, in my header file and use some functions provided by this library in the implementation file (file.cpp)...
1
by: pallav | last post by:
I have two header files, circuit.h and latch.h that reference each other and are causing a cyclic dependency. latch.h file #include "circuit.h" typedef boost::shared_ptr<struct LatchLatchPtr;...
18
by: StephQ | last post by:
I'm facing the following problem: I'm using the Gnu Scientific Library (it is a C math library), and in particular random number generation algorithms. Example code is: .... gsl_rng * r; .......
1
by: nguillot | last post by:
Hello. If I have the following classes: class B {}; typedef B tB; if A is: class A
0
by: nguillot | last post by:
Yes, by redeclaring the tB typedef in A.h: I really would prefer not to duplicate the typedef, for code maintenance.
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.