BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

#include redundancy

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Language C++)
View previous topic :: View next topic  
Author Message
Stephane Baillargeon
Guest





PostPosted: Sat Apr 28, 2007 6:01 pm    Post subject: #include redundancy Reply with quote



Hello,

I have an #include problem ... I think ...

Here's the code:

Data.h
--------
#ifndef DataH
#define DataH

#include <System.hpp>
#include <list>
#include <map>

#include "User.h"
#include "TypeDefs.h"

struct SData
{
LOCALEMAP *pLoc;// defined in Typedef.h
SQLMAP *pSQL; // defined in Typedef.h
CUser *pUser; // Error typename expected?
};

#endif
==========


User.h
------
#ifndef UserH
#define UserH

#include "TypeDefs.h"
#include "Data.h"

class CUser
{
//...
};

#endif
==========

main.h
------
#ifndef MainH
#define MainH

#include "TypeDefs.h"
#include "Data.h"
#include "User.h"

class Main
{
//...
};

#endif
==========

Class main includes the 3 headers to start with. My question is why do I
get this error in Data.h? Why doesn't it see my class CUser?

Thanks.
Back to top
Stephane Baillargeon
Guest





PostPosted: Sat Apr 28, 2007 7:10 pm    Post subject: Re: #include redundancy Reply with quote



Quote:
I have an #include problem ... I think ...

Data.h
--------
#include "User.h"

User.h
------
#include "Data.h"

I realize this is my problem but can someone tell me how to get around it?
Back to top
Bob Gonder
Guest





PostPosted: Sat Apr 28, 2007 7:51 pm    Post subject: Re: #include redundancy Reply with quote



Stephane Baillargeon wrote:

Quote:
I have an #include problem ... I think ...

Data.h
--------
#include "User.h"

User.h
------
#include "Data.h"

I realize this is my problem but can someone tell me how to get around it?

Good old circular references.
You break the cycle by usng forward references.

Data.h
--------
#ifndef DataH
#define DataH

#include <System.hpp>
#include <list>
#include <map>
#include "TypeDefs.h"

/////////#include "User.h" // circular reference
class CUser; // forward reference.

struct SData
{
LOCALEMAP *pLoc;
SQLMAP *pSQL;
CUser *pUser; // No Error: typename known
};
#endif
Back to top
Alan Bellingham
Guest





PostPosted: Sat Apr 28, 2007 8:07 pm    Post subject: Re: #include redundancy Reply with quote

Stephane Baillargeon <stephane@premiere-supplies.com> wrote:

Quote:
I have an #include problem ... I think ...

You do indeed.

Quote:
Here's the code:

Data.h
--------
#ifndef DataH
#define DataH

#include <System.hpp
#include <list
#include <map

#include "User.h"
#include "TypeDefs.h"

struct SData
{
LOCALEMAP *pLoc;// defined in Typedef.h
SQLMAP *pSQL; // defined in Typedef.h
CUser *pUser; // Error typename expected?
};

#endif
==========

[User.h - which defines CUser, but also #includes Data.h, which includes
User.h, which ...]

What you need is some way to break this cycle, which requires CUser to
be known before you define SData, and vice versa. The way out of this is
known as 'forward declaration', where you tell the compiler that a class
definition will exist sometime in the future, but for now not to worry
its little head about it.

#ifndef DataH
#define DataH

#include <System.hpp>
#include <list>
#include <map>

class CUser; // forward declaration

#include "TypeDefs.h" // Data.h no longer #included

struct SData
{
LOCALEMAP *pLoc;// defined in Typedef.h
SQLMAP *pSQL; // defined in Typedef.h
CUser *pUser; // Error typename expected?
};

#endif

If fact, your declaration as shown above doesn't actually need to know
what a LOCALEMAP or a SQLMAP are either, so you could easily drop the
#inclusion of TypeDefs.h as well. (And System.hpp, list and map aren't
used either.),

Forward declaration doesn't always solve such problems, but the compiler
will tell you about them. Cases are usually when an external class is
used as a base class or member, but in such cases, the class used as a
base or member is included from the one containing or inheriting it.

Alan Bellingham
--
Team Thai Kingdom
<url:http://www.borland.com/newsgroups/> Borland newsgroup descriptions
<url:http://www.borland.com/newsgroups/netiquette.html> netiquette
Back to top
Chris Uzdavinis (TeamB)
Guest





PostPosted: Sat Apr 28, 2007 11:40 pm    Post subject: Re: #include redundancy Reply with quote

Stephane Baillargeon <stephane@premiere-supplies.com> writes:

Quote:
I have an #include problem ... I think ...

Data.h
--------
#include "User.h"

User.h
------
#include "Data.h"

I realize this is my problem but can someone tell me how to get
around it?

The declaration of an incomplete type is the solution. (A "forward
declaration".)

Not only does this tell the compiler "this is a type, but since I'm
only declaring a pointer (or reference) to it and am not actually
needing to know anything about the type, I don't WANT to know anything
about it, other than it exists.

This eliminiates a dependency on everything that User.h includes.
(Whenever something changes, everything that depends on it must be
recompiled. If you can forward declare a type rather than include its
header, it's always a better choice, because you avoid the need to
recompile anytime User.h (and everything it depends on) changes.

That means that every file that includes your Data.h header is not
going to also have to be recompiled whenever anything that User.h
depends upon also changes.

(In the worst possible case, every header includes every header, and
every cpp file only includes its own corresponding header, yet any
change in any header requires rebuilding EVERY file in the project.)

The larger a project gets, the more substantial a savings you can get
by breaking the dependency tree.

--
Chris (TeamB);
Back to top
Dennis Jones
Guest





PostPosted: Sun Apr 29, 2007 8:10 am    Post subject: Re: #include redundancy Reply with quote

"Chris Uzdavinis (TeamB)" <chris (AT) uzdavinis (DOT) com> wrote in message
news:86ps5owddx.fsf (AT) explicit (DOT) atdesk.com...

Quote:
(In the worst possible case, every header includes every header, and
every cpp file only includes its own corresponding header, yet any
change in any header requires rebuilding EVERY file in the project.)

The larger a project gets, the more substantial a savings you can get
by breaking the dependency tree.

The best treatment of this subject (that I know of) is John Lakos'
"Large-Scale C++ Software Design." He goes into great detail discussing
cyclic dependencies, how to measure them, and describes various ways to
prevent them. The book is somewhat dated (some have even gone so far as to
suggest that it was out of date when it was published in 1996), but it is
still a very good (if not lengthy!) read nevertheless, IMO.

- Dennis
Back to top
Clayton Arends
Guest





PostPosted: Mon Apr 30, 2007 5:07 am    Post subject: Re: #include redundancy Reply with quote

Everybody answered correctly. However, unless I'm blind they all left out
one crucial part of forward declarations -- the eventual need to know the
declaration.

This is accomplished by including the necessary file in the CPP that needs
it. In your case you will need to add the include to Data.cpp:

// Data.h
class CUser; // forward declaration

// Data.cpp
#include "User.h"

- Clayton
Back to top
Alan Bellingham
Guest





PostPosted: Mon Apr 30, 2007 2:21 pm    Post subject: Re: #include redundancy Reply with quote

"Clayton Arends" <nospam_claytonarends (AT) hotmail (DOT) com> wrote:

Quote:
Everybody answered correctly. However, unless I'm blind they all left out
one crucial part of forward declarations -- the eventual need to know the
declaration.

Indeed. But the chances are that many files using Data.h won't actually
require User.h, which means a considerable amount of compile-time
decoupling. Do this consistently, and you should find that when User.h
is touched, only those source files that actually need to know the true
definition of CUser will recompile, not all those files that happen to
see a CData.

Quote:
This is accomplished by including the necessary file in the CPP that needs
it. In your case you will need to add the include to Data.cpp:

// Data.h
class CUser; // forward declaration

// Data.cpp
#include "Data.h"
#include "User.h"

I assume that Data.cpp will want to know about Data.h.

Now, User.h may in this case be including it, but my preference (and I
state preference, nothing more, you may disagree) is that when designing
a class, there should be a source/header pair, and that within the
source file, the first include should be the corresponding header.
(After any precompiled headers, if need be.) After that, add any
includes for other headers required by the implementation of the class.
So, the top of one of my source files tends to look like:

... module comments for data.cpp
//----------------------------------------------
#include "precompiledheader.h"
#pragma hdrstop
#include "data.h"
//----------------------------------------------
#include "Other.h"
#include "User.h"
//----------------------------------------------
#include "CPPLib/StringUtil.h"
#include "WinLib/ResourceInst.h"
//----------------------------------------------
#include <map>
#include <vector>
//----------------------------------------------
... local defines, anonymous namespace, implementation, etc

This has four sections - the precompiled headers and module header, then
other headers from *this* project, then headers from my other libraries,
(the root directory for which is on my include path) and finally system
headers. Within each section after the first, I sort them alphabetically
for convenience.

I also try to make sure it still works when the precompiled header
contains nothing at all - so all headers must be idempotent, i.e. able
to stand alone. Since by my scheme data.h must still work when included
before anything else, I soon find out about inter-header requirements.

You're free to disagree - this is just how I do it these days.

Alan Bellingham
--
ACCU Conference 2008: 2-5 April 2008 - Oxford (probably), UK
Back to top
Clayton Arends
Guest





PostPosted: Mon Apr 30, 2007 8:10 pm    Post subject: Re: #include redundancy Reply with quote

Quote:
But the chances are that many files using Data.h won't actually
require User.h, which means a considerable amount of compile-time
decoupling.

No argument. I too use forward declarations all the time not just to get
around the problem of cyclical dependencies.

Quote:
I assume that Data.cpp will want to know about Data.h.

Yes. The important part of my post though was I was showing what lines
needed to be added to the two files.

Quote:
Now, User.h may in this case be including it, but my preference ...
[snip]

This is my preference, too. Though mine is formatted just slightly
differently with system headers coming before project headers.

#include "precompiledheader.h"
#pragma hdrstop

/***********************************************
unitname.cpp

Notes, todos, etc.
***********************************************/

#include "datamodule.h" // if unit is a form
//----------------------------------------------

#include "unitname.h"
#pragma hdrstop // if using the package system
//----------------------------------------------
// Includes for C/C++ headers
#include <stdio> // for example
//----------------------------------------------
// Includes for STL headers
#include <map>
#include <vector>
//----------------------------------------------
// Includes for VCL headers

#include <Dialogs.hpp>
//----------------------------------------------
// Includes for the project
#include "Other.h"
#include "User.h"
//----------------------------------------------

Quote:
Within each section after the first, I sort them alphabetically
for convenience.

Same here. Since we're sharing secrets Wink I do this for logical sections
of code too. All classes or sorted alphabetically in the CPP. All methods
of a class are sorted alphabetically starting with the constructors and
destructor.

Quote:
I also try to make sure it still works when the precompiled header
contains nothing at all

Same here. I have a "#ifndef NO_PCH" in my PCH files so that I can quickly
turn off the PCH in the project options to check for proper dependencies. I
do this every few months during active development of a project.

- Clayton
Back to top
vavan
Guest





PostPosted: Mon May 07, 2007 1:34 pm    Post subject: Re: #include redundancy Reply with quote

On Sat, 28 Apr 2007 14:40:58 -0400, Chris Uzdavinis (TeamB)
<chris (AT) uzdavinis (DOT) com> wrote:

Quote:
The larger a project gets, the more substantial a savings you can get
by breaking the dependency tree.

unfortunately the way bcb ide autogenerates form headers (see msg-id
46374530$1 (AT) newsgroups (DOT) borland.com from Mogens Hansen) practically
disavows that very useful cpp decoupling technique. that would be
great if they changed such unproductive behaviour

--
Vladimir Ulchenko aka vavan
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Language C++) 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.