473,508 Members | 2,283 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Including related files

Hi,
I have what feels like a really stupid question and I'm sorry if it is
asked a lot.
Imagine I have two classes cShip and cPassenger. They each have a
definition in their own header cShip.h and cPassenger.h and their
implementation in cShip.cpp and cPassenger.cpp. Now here is the header
file for each:

#ifndef CSHIP_H
#define CSHIP_H

class cShip
{
...
cPassenger * owner;
...
};

#endif

------Next file

#ifndef CPASSENGER_H
#define CPASSENGER_H

class cPassenger
{
...
cShip * current_vehicle;
...
};

#endif

Now the problem I have is how to join these files together with includes
such that they compile. (The idea here is that a ship always has an
owner but that a passenger can be in a ship that they don't own).

Sorry if this is a really mundane question,
Connell
Jul 23 '05 #1
21 1382
Connell Gauld wrote:
I have what feels like a really stupid question and I'm sorry if it is
asked a lot.
[...circular dependency question snipped...]


Don't be sorry, just read the FAQ before posting.
You can find it here: http://www.parashift.com/c++-faq-lite/

V
Jul 23 '05 #2
An owner may not be a passenger, so it may make more sense to have a
separate cOwner and cPassenger class. But to get circular references to
compile, you can simply use a forward declaration:

#ifndef CSHIP_H
#define CSHIP_H

class cPassenger;

class cShip
{
...
cPassenger * owner;
...
};

#endif

#ifndef CPASSENGER_H
#define CPASSENGER_H

class cShip;

class cPassenger
{
...
cShip * current_vehicle;
...
};

#endif

This could cause you some problems though if any part of the class
declaration relies on deeper knowledge about the forward declared
class. A forward declaration only gives you the name of the class, not
any details about data members or member functions.

Jul 23 '05 #3
* Connell Gauld:

I have what feels like a really stupid question and I'm sorry if it is
asked a lot.
Not at all, it's a good question.

There are a host of very _similar_ questions that all involve
circular dependencies.

In your case the usual solution, forward declarations, is _not_
appropriate.

Imagine I have two classes cShip and cPassenger. They each have a
definition in their own header cShip.h and cPassenger.h and their
implementation in cShip.cpp and cPassenger.cpp. Now here is the header
file for each:

#ifndef CSHIP_H
#define CSHIP_H

class cShip
{
...
cPassenger * owner;
...
};

#endif

------Next file

#ifndef CPASSENGER_H
#define CPASSENGER_H

class cPassenger
{
...
cShip * current_vehicle;
...
};

#endif

Now the problem I have is how to join these files together with includes
such that they compile. (The idea here is that a ship always has an
owner but that a passenger can be in a ship that they don't own).


What you have is a design problem, not (just) a technical circular
dependency problem.

Let the owner of a ship be a cPerson.

Let cPassenger be a class derived from cPerson, and voilą, problem solved;
you then have

cShip depends on CPerson
cPassenger depends on cShip and cPerson

Later on you might consider the case where the owner might be a person _or_
a corporation.

With that twist it gets more interesting... ;-)

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #4
Connell Gauld wrote:
....

Now the problem I have is how to join these files together with includes
such that they compile. (The idea here is that a ship always has an
owner but that a passenger can be in a ship that they don't own).


Ownership (no pun intended) is somthing you need to manage with the
code, not the declaration (if you were using smart pointers you could do
this otherwise).

As for the declaration issues - you need to forward declare the class
you're referring to - see below.

#ifndef CSHIP_H
#define CSHIP_H

class cPassenger; // declare a class cPassenger

class cShip
{
...
cPassenger * owner;
...
};

#endif

------Next file

#ifndef CPASSENGER_H
#define CPASSENGER_H

class cShip; // declare a class cShip

class cPassenger
{
...
cShip * current_vehicle;
...
};
Jul 23 '05 #5
Alf P. Steinbach wrote:
* Connell Gauld:
I have what feels like a really stupid question and I'm sorry if it is
asked a lot.

Not at all, it's a good question.

There are a host of very _similar_ questions that all involve
circular dependencies.

In your case the usual solution, forward declarations, is _not_
appropriate.


Huh?
[...]

Jul 23 '05 #6
* Victor Bazarov:
Alf P. Steinbach wrote:
* Connell Gauld:
I have what feels like a really stupid question and I'm sorry if it is
asked a lot.

Not at all, it's a good question.

There are a host of very _similar_ questions that all involve
circular dependencies.

In your case the usual solution, forward declarations, is _not_
appropriate.


Huh?


See the rest of that message, but, since you ask, some background:

It's generally not a good idea to solve design problems by applying
technical kludges to the _symptoms_, whether the kludges be forward
declarations, 'friend', 'void*', C-style casts, or whatever.

Such "solutions" come back to haunt you, and also they typically
yield more complex, non-maintainable code in the first place, because you
missed out on sensible abstraction opportunities (which simplify things).

Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #7
Alf P. Steinbach wrote:
* Victor Bazarov:
Alf P. Steinbach wrote:
* Connell Gauld:
I have what feels like a really stupid question and I'm sorry if it is
asked a lot.
Not at all, it's a good question.

There are a host of very _similar_ questions that all involve
circular dependencies.

In your case the usual solution, forward declarations, is _not_
appropriate.
Huh?

See the rest of that message, but, since you ask, some background:

It's generally not a good idea to solve design problems by applying
technical kludges to the _symptoms_, whether the kludges be forward
declarations, 'friend', 'void*', C-style casts, or whatever.


What makes you think there *is* a design problem there? The need to use
a "technical kludge" is *not* necessarily an indication of a design flaw.
Just like 'friend' and 'void*' and 'dynamic_cast', forward declarations
are there to be used to _accommodate_ certain design decisions, not to be
avoided at all costs.
Such "solutions" come back to haunt you, and also they typically
yield more complex, non-maintainable code in the first place, because you
missed out on sensible abstraction opportunities (which simplify things).


No! What you did suggest was, in fact, a kludge. If two classes do
depend on each other, the model in question is _fine_, it is perfectly
OK to have a pointer to A in B and a pointer to B in A. And, yes, the
only clean way to resolve the reference "problems" is in the FAQ.

Introducing a non-existent design elements just to avoid using some
language features you might be finding "inappropriate" for whatever
reason, is definitely a mistake.

Design comes first, language-specific implementation comes second.

V
Jul 23 '05 #8
* Victor Bazarov:

Design comes first, language-specific implementation comes second.


Right.

I gather all that about likes and dislikes that I snipped abvoe, a
completely unwarranted speculation about my thinking (I don't think that
way), was really about your earlier posting, posted almost at the same time
as mine, where you failed to notice it was a design problem... ;-)

Check the design again, then tell me it's reasonable that a boat's owner
must be a passenger.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #9
"Alf P. Steinbach" wrote:
[snip]
Let the owner of a ship be a cPerson.
OK.
(Side note: Every cPerson owns a ship? I don't think so.
So I take it for granted that you wanted to have a cPerson class
and derive a COwner class from it)

Let cPassenger be a class derived from cPerson, and voilą, problem solved;
you then have

cShip depends on CPerson
cPassenger depends on cShip and cPerson

Later on you might consider the case where the owner might be a person _or_
a corporation.


Well. Eventually he will come to the point where his ships actually transport
cPassenger-s.

So this will end up in

cShip depends on COwner and cPassenger
cOwner depends on cShip
cPassenger depends on cShip

Same problem. The design is better, but the circular dependency stays
the same.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 23 '05 #10
Alf P. Steinbach wrote:
* Victor Bazarov:
Design comes first, language-specific implementation comes second.

Right.

I gather all that about likes and dislikes that I snipped abvoe, a
completely unwarranted speculation about my thinking (I don't think that
way), was really about your earlier posting, posted almost at the same time
as mine, where you failed to notice it was a design problem... ;-)


*What* design problem?
Check the design again, then tell me it's reasonable that a boat's owner
must be a passenger.


You're trying to read more than the OP has ever thought of presenting.
Whether the design is reasonable is _not_ the topic of this discussion.
For all it's worth, the question could be about A having a B* in it and
B having an A*.

*You* read the original post again. It doesn't say "My boat ownership
model demands to have two classes 'cPassenger' and 'cShip' and here is
the relationship between them". It says "IMAGINE I have two classes..."
(emphasis added).

I don't dispute that there can be design flaws. What I am disputing that
the need to use a forward declaration is an automatic indication (symptom)
of a bad design.

Besides, if you want to talk design, perhaps you should invite the OP to
comp.object? He asked for a language-specific solution and he got it.

V
Jul 23 '05 #11
* Victor Bazarov:
It says "IMAGINE I have two classes..." (emphasis added).
So, the example is what one should imagine, then. ;-)

I don't dispute that there can be design flaws.
Good, we're converging toward agreement here.

What I am disputing that the need to use a forward
declaration is an automatic indication (symptom) of a bad design.
There we agree completely! :-)

Now who the ... said that?

Give him to me (I've got my hammer ready); I'll bash him!

Besides, if you want to talk design, perhaps you should invite the OP to
comp.object? He asked for a language-specific solution and he got it.
As you wrote earlier,

Design comes first, language-specific implementation comes second.

Using a language correctly or reasonably has very much to do with the design
level. Otherwise we wouldn't frown on 'void*' and the like. Remove the
design level and you could as well use only the 'asm{ ... }' feature.

So, IMO the design level is the first one should focus on except when a
problem is stated without any connection to an application, e.g. like your
A/B example, and I think you agree with that.

Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #12
* Karl Heinz Buchegger:
"Alf P. Steinbach" wrote:

[snip]

Let the owner of a ship be a cPerson.


OK.
(Side note: Every cPerson owns a ship? I don't think so.
So I take it for granted that you wanted to have a cPerson class
and derive a COwner class from it)


Nope.

That "nope" follows from the minimalist guideline.

If there isn't a problem, don't solve it (yet), and there isn't a problem:
a ship can have a person as owner without every person being an owner.

A cOwner class is only necessary if an owner has some extra attributes
or different behavior than a person.

So far nothing has indicated that owners do, but in the OP's model
passengers have, compared to persons.

Let cPassenger be a class derived from cPerson, and voilą, problem solved;
you then have

cShip depends on CPerson
cPassenger depends on cShip and cPerson

Later on you might consider the case where the owner might be a person _or_
a corporation.


Well. Eventually he will come to the point where his ships actually transport
cPassenger-s.

So this will end up in

cShip depends on COwner and cPassenger
cOwner depends on cShip
cPassenger depends on cShip

Same problem. The design is better, but the circular dependency stays
the same.


No, and yes.

Different but in some respects similar problem: different solution.

Details matter, IMHO.

I think it's interesting that with cPerson (I don't like prefixes!)
one can also more easily see a solution to this new slightly different
problem, where one detail is exemplified by: "what class should contain the
embark() member function?". Should we write ship.embark(passenger) or
should we write passenger.embarkOn(ship), or what?

I think I'd land on the "or what", at least as fundamental implementation;
when thinking about the design level a person isn't forever a passenger,
it's just a transient property, and it can even be an implied property that
shouldn't then be represented explicitly in the cPerson objects except as an
optimization if it turns out that optimization is necessary.

General summary: circular dependencies sometimes arise from bad design,
and generalizing the model to cover more is one possible way to remove such
a dependency (not always applicable, but often enough).

The first generalization, to add the Person concept; the second, to extend
the model to cover cases where persons aren't passengers all the time.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #13
Alf P. Steinbach wrote:
[...]
So, IMO the design level is the first one should focus on except when a
problem is stated without any connection to an application, e.g. like your
A/B example, and I think you agree with that.


Well, no. You need to remember that C++ is a multi-paradigm language.
OO is not the end of its application. You also need to remember that
we are in a _language_ newsgroup, and while design is important, and it
does come first, when asked a *simple* language question, one shouldn't
instead go off on a tangent and begin discussing design when no design
discussion is requested.

It's all about assumptions. I (and a couple of other folks) assumed
that the OP knows what he's doing, and while there can always be some
not-so-obvious misconceptions somebody might have about the model he is
using, it's up to him to recognize that and ask for comments on it. You
OTOH assumed that the OP does *not* know what he's doing. Now, while it
is up to the OP to decide whose assumption is the correct one (and I am
not asking about it 'coz I really don't care), with all other things
being equal, a plain answer to the question posed is _better_ than any
other off-on-a-tangent speculation.

If you don't think so, fine. If you reluctantly agree, fine. If you
now see the light and admit your off-on-a-tangent-ness, fine. In any
case, I am not interested in discussing this any more, at least here.
I've stated my point of view, explaining it further makes no sense to me.

Thanks for reading.

V
Jul 23 '05 #14
* Victor Bazarov:
Alf P. Steinbach wrote:
[...]
So, IMO the design level is the first one should focus on except when a
problem is stated without any connection to an application, e.g. like your
A/B example, and I think you agree with that.
Well, no. You need to remember that C++ is a multi-paradigm language.
OO is not the end of its application. You also need to remember that
we are in a _language_ newsgroup, and while design is important, and it
does come first, when asked a *simple* language question, one shouldn't
instead go off on a tangent and begin discussing design when no design
discussion is requested.


One should give the best available answer, and here that was design.

That's not going off on a tanget: it's ordaining the best medicine.

This medicine also happens to be a general technique not AFAIK mentioned in
the FAQ, so it's interesting in its own right.

It's all about assumptions. I (and a couple of other folks) assumed
that the OP knows what he's doing, and while there can always be some
not-so-obvious misconceptions somebody might have about the model he is
using, it's up to him to recognize that and ask for comments on it. You
OTOH assumed that the OP does *not* know what he's doing.
Naturally; he or she wouldn't ask if he or she knew.

Do you see that now?

Now, while it
is up to the OP to decide whose assumption is the correct one (and I am
not asking about it 'coz I really don't care), with all other things
being equal, a plain answer to the question posed is _better_ than any
other off-on-a-tangent speculation.


What I gave was the plainest, best answer.

Advicing to use forward declarations, void* pointers or whatever
tecnical kludges that can hide symptoms, but not cure, and that
can and probably will exacerbate the problems, is ungood.

Especially when the cure is so exceedingly simple.

Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #15
Alf P. Steinbach wrote:
[...]
Especially when the cure is so exceedingly simple.


ROFLMAO Yeah, right...
Jul 23 '05 #16
* Victor Bazarov:
Alf P. Steinbach wrote:
[...]
Especially when the cure is so exceedingly simple.


ROFLMAO Yeah, right...


Sharpen up, Victor.

It _is_ exceedingly simple.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #17
Alf P. Steinbach wrote:
* Victor Bazarov:
Alf P. Steinbach wrote:
[...]
Especially when the cure is so exceedingly simple.


ROFLMAO Yeah, right...

Sharpen up, Victor.

It _is_ exceedingly simple.


ROFLMAO To whom?

While I have to admit this *is* amusing... I got no time for this.
Jul 23 '05 #18
shouldn't the declaration and implementation be in the header?
richard
"Connell Gauld" <co*****@freebreakfast.co.uk> wrote in message
news:d7**********@newsg4.svr.pol.co.uk...
Hi,
I have what feels like a really stupid question and I'm sorry if it is
asked a lot.
Imagine I have two classes cShip and cPassenger. They each have a
definition in their own header cShip.h and cPassenger.h and their
implementation in cShip.cpp and cPassenger.cpp. Now here is the header
file for each:

#ifndef CSHIP_H
#define CSHIP_H

class cShip
{
...
cPassenger * owner;
...
};

#endif

------Next file

#ifndef CPASSENGER_H
#define CPASSENGER_H

class cPassenger
{
...
cShip * current_vehicle;
...
};

#endif

Now the problem I have is how to join these files together with includes
such that they compile. (The idea here is that a ship always has an owner
but that a passenger can be in a ship that they don't own).

Sorry if this is a really mundane question,
Connell

Jul 23 '05 #19
In message <42*****************@news.individual.net>, Alf P. Steinbach
<al***@start.no> writes

It's generally not a good idea to solve design problems by applying
technical kludges to the _symptoms_, whether the kludges be forward
declarations, 'friend', 'void*', C-style casts, or whatever.


Hmm.

Friend's a kludge because it breaks encapsulation.
void* and casts are kludges because they break type safety.

But what does a forward declaration break?

--
Richard Herring
Jul 23 '05 #20
Richard Herring wrote:
In message <42*****************@news.individual.net>, Alf P. Steinbach
<al***@start.no> writes

It's generally not a good idea to solve design problems by applying
technical kludges to the _symptoms_, whether the kludges be forward
declarations, 'friend', 'void*', C-style casts, or whatever.
Hmm.

Friend's a kludge because it breaks encapsulation.


It's only a kluge if you use it incorrectly. See FAQ 14.2.
void* and casts are kludges because they break type safety.
Yep, that's why the C++ cast operators are so ugly. :)
But what does a forward declaration break?


You'll often see a forward-declared class used to solve the problem of
mutual inclusion, i.e., when two headers #include each other. The
forward declaration allows it to compile, but more often than not
you're looking at a design problem.

Kristo

Jul 23 '05 #21
In message <11**********************@g14g2000cwa.googlegroups .com>,
Kristo <kr*******@gmail.com> writes
Richard Herring wrote:
In message <42*****************@news.individual.net>, Alf P. Steinbach
<al***@start.no> writes
>
>It's generally not a good idea to solve design problems by applying
>technical kludges to the _symptoms_, whether the kludges be forward
>declarations, 'friend', 'void*', C-style casts, or whatever.
Hmm.

Friend's a kludge because it breaks encapsulation.


It's only a kluge if you use it incorrectly. See FAQ 14.2.


Indeed. I was just trying to find a reason why it might be called a
kludge at all.
void* and casts are kludges because they break type safety.


Yep, that's why the C++ cast operators are so ugly. :)
But what does a forward declaration break?


You'll often see a forward-declared class used to solve the problem of
mutual inclusion, i.e., when two headers #include each other. The
forward declaration allows it to compile, but more often than not
you're looking at a design problem.


At that design level, yes, there may in some cases (I think "more often
than not" is too strong) be a problem with mutual *inclusion*.

But it's much more frequently used to solve legitimate problems of
mutual *reference*, cases where objects of two mutually-dependent
classes genuinely need to contain pointers or references to each other,
but nothing more; perhaps the most obvious is when a child needs to know
who its parent is.

But that wasn't really my point. The forward declaration itself doesn't
break anything[*]; on the contrary, it conveys the minimum possible
information about a class, hiding all the unnecessary detail. I'd say
that was a good and useful thing to be able to do, and it's unfair to
give it the same derogatory label as tricks involving casting to void*.

[*] except (in a different sense of the word) mutual-inclusion loops!

--
Richard Herring
Jul 23 '05 #22

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

Similar topics

4
1808
by: WindAndWaves | last post by:
Hi Gurus I hope I am going to make sense with this question: I have an html page that I have turned into a php page with a bit of php code above the html (connect to database, massage data a...
0
286
by: David | last post by:
How can set of XML files be validated by one XML schema? To be more details, for instance, I created a SML schema with complex type Customer and Order in Orders.xsd. Table Order is related to...
0
3271
by: bettervssremoting | last post by:
To view the full article, please visit http://www.BetterVssRemoting.com Better VSS Remote Access Tool including SourceOffSite, SourceAnyWhere and VSS Remoting This article makes a detailed...
8
3033
by: nrhayyal | last post by:
Hi c++ Gurus, Need your blessing. while testing few aspects with respect to header file inclusions, i observed few things which i would like to share with you. i have a file sqlca.h in which a...
7
1438
by: Cyberwolf | last post by:
Hi all I'm having a strange problem when upgrading the content management system eZ publish from PHP 4.4 to PHP 5.1. Some cache files related to i18n are included with the "include" function,...
3
5261
by: Steven Nagy | last post by:
Hi all, ASP.NET : Framework 2.0 - C# A recent addition to my code generater will create GridView's and ObjectDataSource's in a control (ASCX). So the code gen creates an ascx, ascx.cs,...
6
1759
Sieira
by: Sieira | last post by:
I have the following files: netfunc.h: typedef struct{ char data; int n; }packet;
65
5019
by: Hongyu | last post by:
Dear all: I am trying to write to a file with full directory name and file name specified (./outdir/mytestout.txt where . is the current directory) in C programming language and under Unix, but...
3
2562
by: KIRAN | last post by:
Hello all, My question is about the way of including header files(*.h) in source files (*.c) I have three folders, -build ( for project makefiles) -include ( for *.h files) -src (for *.c...
0
7323
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
7379
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...
1
7038
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
5625
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,...
1
5049
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4706
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3192
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
1
763
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
415
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

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.