 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Stephane Baillargeon Guest
|
Posted: Sat Apr 28, 2007 6:01 pm Post subject: #include redundancy |
|
|
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
|
Posted: Sat Apr 28, 2007 7:10 pm Post subject: Re: #include redundancy |
|
|
| 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
|
Posted: Sat Apr 28, 2007 7:51 pm Post subject: Re: #include redundancy |
|
|
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
|
Posted: Sat Apr 28, 2007 8:07 pm Post subject: Re: #include redundancy |
|
|
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
|
Posted: Sat Apr 28, 2007 11:40 pm Post subject: Re: #include redundancy |
|
|
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
|
Posted: Sun Apr 29, 2007 8:10 am Post subject: Re: #include redundancy |
|
|
"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
|
Posted: Mon Apr 30, 2007 5:07 am Post subject: Re: #include redundancy |
|
|
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
|
Posted: Mon Apr 30, 2007 2:21 pm Post subject: Re: #include redundancy |
|
|
"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
|
Posted: Mon Apr 30, 2007 8:10 pm Post subject: Re: #include redundancy |
|
|
| 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 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
|
Posted: Mon May 07, 2007 1:34 pm Post subject: Re: #include redundancy |
|
|
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 |
|
 |
|
|
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
|
|