471,585 Members | 1,169 Online
Bytes | Software Development & Data Engineering Community
Post +

Home Posts Topics Members FAQ

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

#include verse class class_name

I will assume many people reading this would never create anything similar
to the example below. So let me preface this with _*IF*_ you were in a
situation where you had to chose between using #includes or forward
declaring each class in diamond.h, which would you choose? Why?

If there is something fundamentally wrong with the way I've approached the
structure of this example, I am interested to know. As for preferences and
tastes, I would really like to stay focused on the question above.

//north.cpp
#include "north.h"
namespace diamond {
North::North(){}
North::~North(){}
};

//east.cpp
#include "east.h"
namespace diamond {
East::East() : North(){}
East::~East(){}
};

//west.cpp
#include "west.h"
namespace diamond {
West::West() : North(){}
West::~West(){}
};

//south.cpp
#include "south.h"
namespace diamond {
South::South(): East(), West(){}
South::~South(){}
};

//diamond.cpp
#include "diamond.h"
namespace diamond {
Diamond::Diamond(){}
Diamond::~Diamond(){}
};

//north.h
#ifndef DIAMONDNORTH_H
#define DIAMONDNORTH_H
namespace diamond {
class North{
public:
North();
~North();
};
};
#endif

//east.h
#ifndef DIAMONDEAST_H
#define DIAMONDEAST_H
#include "north.h"
namespace diamond {
class East : virtual public North
{
public:
East();
~East();
};
};
#endif

//west.h
#ifndef DIAMONDWEST_H
#define DIAMONDWEST_H
#include "north.h"
namespace diamond {
class West : virtual public North
{
public:
West();
~West();
};
};
#endif

//south.h
#ifndef DIAMONDSOUTH_H
#define DIAMONDSOUTH_H
#include "east.h"
#include "west.h"
namespace diamond {
class South : virtual public East, virtual public West
{
public:
South();
~South();
};
};
#endif

//diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H
namespace diamond
{
class Diamond
{
public:
Diamond();
~Diamond();
private:
East e;
North n;
West w;
South s;
};
};

--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #1
28 1917
Steven T. Hatton wrote:
I will assume many people reading this would never create anything similar
to the example below. So let me preface this with _*IF*_ you were in a
situation where you had to chose between using #includes or forward
declaring each class in diamond.h, which would you choose? Why?
As it turns out, in this case I have to use the #includes. I'm not 100% sure
why that is. I just know it didn't compile, and gave an error saying the
class definitions were incomplete.
//diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H
namespace diamond
{ /*didn't work*/
class East
class West
class North
class South class Diamond
{
public:
Diamond();
~Diamond();
private:
East e;
North n;
West w;
South s;
};
};


--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #2
Steven T. Hatton wrote:
I will assume many people reading this would never create anything similar
to the example below. So let me preface this with _*IF*_ you were in a
situation where you had to chose between using #includes or forward
declaring each class in diamond.h, which would you choose? Why?
As it turns out, in this case I have to use the #includes. I'm not 100% sure
why that is. I just know it didn't compile, and gave an error saying the
class definitions were incomplete.
//diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H
namespace diamond
{ /*didn't work*/
class East
class West
class North
class South class Diamond
{
public:
Diamond();
~Diamond();
private:
East e;
North n;
West w;
South s;
};
};


--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #3
Steven T. Hatton wrote:
[snip]

Prefer forward declarations. If you include (unnecessary) other headers
in yours you will slow down compilation without any real benefit.
/*didn't work*/
class East
class West
class North
class South

[snip]
East e;
North n;
West w;
South s;

[snip]

That's because you stored them by value. The compiler needs to determine
the size of your class.. how can it do this for diamond without the full
data about East, West, etc.

You can only get away with forward declarations in the following
circumstances (might have missed a few):

1) Your class/header never *contains* the forward declared class by value.

2) Your class/header never has a method/function that takes the forward
declared class by value (reference or pointer is fine, as is returning
it by value).

3) Your header never uses the forward declared class for scope
resolution (e.g. East::whatever).

4) You do not inherit from the forward declared class.

To get around this you can use the compiler firewall idiom:

// diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H

namespace diamond
{
class Diamond
{
public:
Diamond();
~Diamond();

private:
// If these aren't private then they need special
// handling to make a copy of the pointer below.
Diamond( const Diamond& ); // Not implemented
Diamond& operator=( const Diamond& ); // Not implemented.

struct Impl;
Impl* impl_;
};
}

#endif // !DIAMONDDIAMOND_H

// diamond.cpp
#include "diamond.h"
#include "north.h"
#include "south.h"
#include "east.h"
#include "west.h"

namespace diamond
{
struct Diamond::Impl
{
// Any constructor/extra members you want here.

East e;
North n;
West w;
South s;
};

Diamond::Diamond() : impl_( new Impl ) {}
Diamond::~Diamond() { delete impl_; }
}

Personally I use a boost::scoped_ptr to hold the impl_ pointer so I
don't have to worry about deleting it. Note also that you need extra
care if the object will be copyable.

If you do want to use scoped_ptr, you must remember to have your
constructor and destructor *after* the Impl class definition. Otherwise
the compiler complains about incomplete types.

See also:

http://www.gotw.ca/gotw/024.htm
http://www.gotw.ca/gotw/028.htm
http://c2.com/cgi/wiki?PimplIdiom

...and many others available from google. The guru of the week archive is
filled with this kind of stuff (www.gotw.ca/gotw).

-- Pete
Jul 22 '05 #4
Steven T. Hatton wrote:
[snip]

Prefer forward declarations. If you include (unnecessary) other headers
in yours you will slow down compilation without any real benefit.
/*didn't work*/
class East
class West
class North
class South

[snip]
East e;
North n;
West w;
South s;

[snip]

That's because you stored them by value. The compiler needs to determine
the size of your class.. how can it do this for diamond without the full
data about East, West, etc.

You can only get away with forward declarations in the following
circumstances (might have missed a few):

1) Your class/header never *contains* the forward declared class by value.

2) Your class/header never has a method/function that takes the forward
declared class by value (reference or pointer is fine, as is returning
it by value).

3) Your header never uses the forward declared class for scope
resolution (e.g. East::whatever).

4) You do not inherit from the forward declared class.

To get around this you can use the compiler firewall idiom:

// diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H

namespace diamond
{
class Diamond
{
public:
Diamond();
~Diamond();

private:
// If these aren't private then they need special
// handling to make a copy of the pointer below.
Diamond( const Diamond& ); // Not implemented
Diamond& operator=( const Diamond& ); // Not implemented.

struct Impl;
Impl* impl_;
};
}

#endif // !DIAMONDDIAMOND_H

// diamond.cpp
#include "diamond.h"
#include "north.h"
#include "south.h"
#include "east.h"
#include "west.h"

namespace diamond
{
struct Diamond::Impl
{
// Any constructor/extra members you want here.

East e;
North n;
West w;
South s;
};

Diamond::Diamond() : impl_( new Impl ) {}
Diamond::~Diamond() { delete impl_; }
}

Personally I use a boost::scoped_ptr to hold the impl_ pointer so I
don't have to worry about deleting it. Note also that you need extra
care if the object will be copyable.

If you do want to use scoped_ptr, you must remember to have your
constructor and destructor *after* the Impl class definition. Otherwise
the compiler complains about incomplete types.

See also:

http://www.gotw.ca/gotw/024.htm
http://www.gotw.ca/gotw/028.htm
http://c2.com/cgi/wiki?PimplIdiom

...and many others available from google. The guru of the week archive is
filled with this kind of stuff (www.gotw.ca/gotw).

-- Pete
Jul 22 '05 #5
Pete Vidler wrote:
That's because you stored them by value. The compiler needs to determine
the size of your class.. how can it do this for diamond without the full
data about East, West, etc.
Based on that, I tried putting the other includes /before/ #include
diamond.h in diamond.cpp. That compiled without even needing forward
declarations. I've already expressed my fondness for headers, so there's no
point in repetition.

#include "east.h"
#include "north.h"
#include "south.h"
#include "west.h"
#include "diamond.h"

namespace diamond
{

Diamond::Diamond(): n(),e(),w(),s()
{}

Diamond::~Diamond()
{}

};

To get around this you can use the compiler firewall idiom:

// diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H

namespace diamond
{
class Diamond
{
public:
Diamond();
~Diamond();

private:
// If these aren't private then they need special
// handling to make a copy of the pointer below.
Diamond( const Diamond& ); // Not implemented
Diamond& operator=( const Diamond& ); // Not implemented.

struct Impl;
Impl* impl_;
};
}

#endif // !DIAMONDDIAMOND_H

// diamond.cpp
#include "diamond.h"
#include "north.h"
#include "south.h"
#include "east.h"
#include "west.h"

namespace diamond
{
struct Diamond::Impl
{
// Any constructor/extra members you want here.

East e;
North n;
West w;
South s;
};

Diamond::Diamond() : impl_( new Impl ) {}
Diamond::~Diamond() { delete impl_; }
}
This looks like a common approach used for implementing APIs in Java.
Personally I use a boost::scoped_ptr to hold the impl_ pointer so I
don't have to worry about deleting it. Note also that you need extra
care if the object will be copyable.

If you do want to use scoped_ptr, you must remember to have your
constructor and destructor *after* the Impl class definition. Otherwise
the compiler complains about incomplete types.

See also:
This explains the use with API implementations:
http://www.gotw.ca/gotw/024.htm


"In C++, when anything in a class definition changes (even private members)
all users of that class must be recompiled. To reduce these dependencies, a
common technique is to use an opaque pointer to hide some of the
implementation details:"

--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #6
Pete Vidler wrote:
That's because you stored them by value. The compiler needs to determine
the size of your class.. how can it do this for diamond without the full
data about East, West, etc.
Based on that, I tried putting the other includes /before/ #include
diamond.h in diamond.cpp. That compiled without even needing forward
declarations. I've already expressed my fondness for headers, so there's no
point in repetition.

#include "east.h"
#include "north.h"
#include "south.h"
#include "west.h"
#include "diamond.h"

namespace diamond
{

Diamond::Diamond(): n(),e(),w(),s()
{}

Diamond::~Diamond()
{}

};

To get around this you can use the compiler firewall idiom:

// diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H

namespace diamond
{
class Diamond
{
public:
Diamond();
~Diamond();

private:
// If these aren't private then they need special
// handling to make a copy of the pointer below.
Diamond( const Diamond& ); // Not implemented
Diamond& operator=( const Diamond& ); // Not implemented.

struct Impl;
Impl* impl_;
};
}

#endif // !DIAMONDDIAMOND_H

// diamond.cpp
#include "diamond.h"
#include "north.h"
#include "south.h"
#include "east.h"
#include "west.h"

namespace diamond
{
struct Diamond::Impl
{
// Any constructor/extra members you want here.

East e;
North n;
West w;
South s;
};

Diamond::Diamond() : impl_( new Impl ) {}
Diamond::~Diamond() { delete impl_; }
}
This looks like a common approach used for implementing APIs in Java.
Personally I use a boost::scoped_ptr to hold the impl_ pointer so I
don't have to worry about deleting it. Note also that you need extra
care if the object will be copyable.

If you do want to use scoped_ptr, you must remember to have your
constructor and destructor *after* the Impl class definition. Otherwise
the compiler complains about incomplete types.

See also:
This explains the use with API implementations:
http://www.gotw.ca/gotw/024.htm


"In C++, when anything in a class definition changes (even private members)
all users of that class must be recompiled. To reduce these dependencies, a
common technique is to use an opaque pointer to hide some of the
implementation details:"

--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #7
Steven T. Hatton wrote:
Pete Vidler wrote:
That's because you stored them by value. The compiler needs to determine
the size of your class.. how can it do this for diamond without the full
data about East, West, etc.
Based on that, I tried putting the other includes /before/ #include
diamond.h in diamond.cpp. That compiled without even needing forward
declarations. I've already expressed my fondness for headers, so there's no
point in repetition.

#include "east.h"
#include "north.h"
#include "south.h"
#include "west.h"
#include "diamond.h"


This does not solve your problem. The diamond.h file still requires
those headers, so every source file that includes it will need to
include those headers first. You just shifted the problem onto the
people (and source files) that use your headers.

Much better to use the compiler firewall idiom to free your header file
from requiring east.h, south.h, etc. This way source files that include
diamond.h only need to inlude those headers that are actually required
by that source file (and not by the header).

I believe it's good practice for headers to be self contained. This
means that everything required by the header should be contained in the
header (either by being in the header, being forward declared or by
being #included). In other words, you should be able to #include the
header at the very top of any source file and not get errors.

[snip] This looks like a common approach used for implementing APIs in Java.
I have no idea what you're talking about.

[snip] This explains the use with API implementations:
http://www.gotw.ca/gotw/024.htm


"In C++, when anything in a class definition changes (even private members)
all users of that class must be recompiled. To reduce these dependencies, a
common technique is to use an opaque pointer to hide some of the
implementation details:"


What does this have to do with Java APIs?

-- Pete
Jul 22 '05 #8
Steven T. Hatton wrote:
Pete Vidler wrote:
That's because you stored them by value. The compiler needs to determine
the size of your class.. how can it do this for diamond without the full
data about East, West, etc.
Based on that, I tried putting the other includes /before/ #include
diamond.h in diamond.cpp. That compiled without even needing forward
declarations. I've already expressed my fondness for headers, so there's no
point in repetition.

#include "east.h"
#include "north.h"
#include "south.h"
#include "west.h"
#include "diamond.h"


This does not solve your problem. The diamond.h file still requires
those headers, so every source file that includes it will need to
include those headers first. You just shifted the problem onto the
people (and source files) that use your headers.

Much better to use the compiler firewall idiom to free your header file
from requiring east.h, south.h, etc. This way source files that include
diamond.h only need to inlude those headers that are actually required
by that source file (and not by the header).

I believe it's good practice for headers to be self contained. This
means that everything required by the header should be contained in the
header (either by being in the header, being forward declared or by
being #included). In other words, you should be able to #include the
header at the very top of any source file and not get errors.

[snip] This looks like a common approach used for implementing APIs in Java.
I have no idea what you're talking about.

[snip] This explains the use with API implementations:
http://www.gotw.ca/gotw/024.htm


"In C++, when anything in a class definition changes (even private members)
all users of that class must be recompiled. To reduce these dependencies, a
common technique is to use an opaque pointer to hide some of the
implementation details:"


What does this have to do with Java APIs?

-- Pete
Jul 22 '05 #9
Pete Vidler wrote:
This does not solve your problem. The diamond.h file still requires
those headers, so every source file that includes it will need to
include those headers first. You just shifted the problem onto the
people (and source files) that use your headers.
So I learned the hard way. As soon as I tried to use it from outside of the
implementation, I was back at square one.

[snip good advice, etc.]
What does this have to do with Java APIs?


I would really have to do some digging to determine how closely the
approaches correspond, but here is one example of API amd implementation
done in Java:
http://xml.apache.org/xerces2-j/javadocs/api/index.html
http://xml.apache.org/xerces2-j/java...es2/index.html
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #10
Pete Vidler wrote:
This does not solve your problem. The diamond.h file still requires
those headers, so every source file that includes it will need to
include those headers first. You just shifted the problem onto the
people (and source files) that use your headers.
So I learned the hard way. As soon as I tried to use it from outside of the
implementation, I was back at square one.

[snip good advice, etc.]
What does this have to do with Java APIs?


I would really have to do some digging to determine how closely the
approaches correspond, but here is one example of API amd implementation
done in Java:
http://xml.apache.org/xerces2-j/javadocs/api/index.html
http://xml.apache.org/xerces2-j/java...es2/index.html
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #11

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Io********************@speakeasy.net...
Steven T. Hatton wrote:
I will assume many people reading this would never create anything similar to the example below. So let me preface this with _*IF*_ you were in a
situation where you had to chose between using #includes or forward
declaring each class in diamond.h, which would you choose? Why?
As it turns out, in this case I have to use the #includes. I'm not 100%

sure why that is. I just know it didn't compile, and gave an error saying the
class definitions were incomplete.
//diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H
namespace diamond
{

/*didn't work*/
class East
class West
class North
class South
class Diamond
{
public:
Diamond();
~Diamond();
private:
East e;
North n;
West w;
South s;
};
};


--


You could store pointers instead of the objects themselves, and instantiate
them in your Diamond constructor. That only requires that your diamond.cpp
file include those other headers instead of including them in diamond.h.
(Of course, then you have to maintain those pointers yourself.)
-Howard

Jul 22 '05 #12

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Io********************@speakeasy.net...
Steven T. Hatton wrote:
I will assume many people reading this would never create anything similar to the example below. So let me preface this with _*IF*_ you were in a
situation where you had to chose between using #includes or forward
declaring each class in diamond.h, which would you choose? Why?
As it turns out, in this case I have to use the #includes. I'm not 100%

sure why that is. I just know it didn't compile, and gave an error saying the
class definitions were incomplete.
//diamond.h
#ifndef DIAMONDDIAMOND_H
#define DIAMONDDIAMOND_H
namespace diamond
{

/*didn't work*/
class East
class West
class North
class South
class Diamond
{
public:
Diamond();
~Diamond();
private:
East e;
North n;
West w;
South s;
};
};


--


You could store pointers instead of the objects themselves, and instantiate
them in your Diamond constructor. That only requires that your diamond.cpp
file include those other headers instead of including them in diamond.h.
(Of course, then you have to maintain those pointers yourself.)
-Howard

Jul 22 '05 #13
Howard wrote:
You could store pointers instead of the objects themselves, and
instantiate
them in your Diamond constructor. That only requires that your
diamond.cpp file include those other headers instead of including them in
diamond.h. (Of course, then you have to maintain those pointers yourself.)
-Howard


That is my prefered approach. I just did it with the value members to see
what happened. Most of the code I've written that does anything other than
dump a few lines of text uses Qt. That takes care of most of the need to
release memory without me having to do anything.

I guess I sould start working some of the problems in TC++PL(SE). Just
reading the text really isn't enough.

--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #14
Howard wrote:
You could store pointers instead of the objects themselves, and
instantiate
them in your Diamond constructor. That only requires that your
diamond.cpp file include those other headers instead of including them in
diamond.h. (Of course, then you have to maintain those pointers yourself.)
-Howard


That is my prefered approach. I just did it with the value members to see
what happened. Most of the code I've written that does anything other than
dump a few lines of text uses Qt. That takes care of most of the need to
release memory without me having to do anything.

I guess I sould start working some of the problems in TC++PL(SE). Just
reading the text really isn't enough.

--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #15
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message news:<Io********************@speakeasy.net>...
Steven T. Hatton wrote:
[redacted]


Because in order to derive from a class, it must be fully defined
(note to Standards Gurus, my terminology may be off).

The compiler must know the full definition of the parent class before
it can be derived, so that it can know about any virtual base classes,
etc... as well as vtbl layout, and how much storage to allocate for
the base class.

Example:

class B;
class D : public B
{
public:
int x;
D(int);

D d;
-- end example

How does the compiler know how big to make D?
Jul 22 '05 #16
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message news:<Io********************@speakeasy.net>...
Steven T. Hatton wrote:
[redacted]


Because in order to derive from a class, it must be fully defined
(note to Standards Gurus, my terminology may be off).

The compiler must know the full definition of the parent class before
it can be derived, so that it can know about any virtual base classes,
etc... as well as vtbl layout, and how much storage to allocate for
the base class.

Example:

class B;
class D : public B
{
public:
int x;
D(int);

D d;
-- end example

How does the compiler know how big to make D?
Jul 22 '05 #17
red floyd wrote:
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:<Io********************@speakeasy.net>...
Steven T. Hatton wrote:
[redacted]
Because in order to derive from a class, it must be fully defined
(note to Standards Gurus, my terminology may be off).

The compiler must know the full definition of the parent class before
it can be derived, so that it can know about any virtual base classes,
etc... as well as vtbl layout, and how much storage to allocate for
the base class.

Example:

class B;
class D : public B
{
public:
int x;
D(int);

D d;
-- end example


My example wasn't using inheritance, but the the same argument probably
applies.
How does the compiler know how big to make D?


That wasn't the part I was uncertain of. It was why the implementation
wasn't available to the compiler at the time. It turns out I probably was
correct regarding the assumption that the implementation was part of the
translation unit. But it seems the forward declaration was not sufficient
to get the compiler to postpone the attempt to process the class
definition. I think the answer is probably in Clause 2 of PL-C++03 (The
Standard).
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #18
red floyd wrote:
"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:<Io********************@speakeasy.net>...
Steven T. Hatton wrote:
[redacted]
Because in order to derive from a class, it must be fully defined
(note to Standards Gurus, my terminology may be off).

The compiler must know the full definition of the parent class before
it can be derived, so that it can know about any virtual base classes,
etc... as well as vtbl layout, and how much storage to allocate for
the base class.

Example:

class B;
class D : public B
{
public:
int x;
D(int);

D d;
-- end example


My example wasn't using inheritance, but the the same argument probably
applies.
How does the compiler know how big to make D?


That wasn't the part I was uncertain of. It was why the implementation
wasn't available to the compiler at the time. It turns out I probably was
correct regarding the assumption that the implementation was part of the
translation unit. But it seems the forward declaration was not sufficient
to get the compiler to postpone the attempt to process the class
definition. I think the answer is probably in Clause 2 of PL-C++03 (The
Standard).
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #19
Steven T. Hatton wrote:
That wasn't the part I was uncertain of. It was why the implementation
wasn't available to the compiler at the time. It turns out I probably was
correct regarding the assumption that the implementation was part of the
translation unit. But it seems the forward declaration was not sufficient
to get the compiler to postpone the attempt to process the class
definition. I think the answer is probably in Clause 2 of PL-C++03 (The
Standard).


In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?

struct A;

struct D {
A a;
};

struct A {};

int main(){}
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #20
Steven T. Hatton wrote:
That wasn't the part I was uncertain of. It was why the implementation
wasn't available to the compiler at the time. It turns out I probably was
correct regarding the assumption that the implementation was part of the
translation unit. But it seems the forward declaration was not sufficient
to get the compiler to postpone the attempt to process the class
definition. I think the answer is probably in Clause 2 of PL-C++03 (The
Standard).


In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?

struct A;

struct D {
A a;
};

struct A {};

int main(){}
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #21

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Wc********************@speakeasy.net...
Steven T. Hatton wrote:
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?

struct A;

struct D {
A a;
};

struct A {};


I think that "formal rule" and "simplest terms" are mutually exclusive,
don't you? :-)

Your compiler error itself is probably the simplest explanation of what rule
is violated.

I don't have the standard to see what the formal rule is, but didn't you
already mention it in another post in this conversation?

-Howard


Jul 22 '05 #22

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Wc********************@speakeasy.net...
Steven T. Hatton wrote:
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?

struct A;

struct D {
A a;
};

struct A {};


I think that "formal rule" and "simplest terms" are mutually exclusive,
don't you? :-)

Your compiler error itself is probably the simplest explanation of what rule
is violated.

I don't have the standard to see what the formal rule is, but didn't you
already mention it in another post in this conversation?

-Howard


Jul 22 '05 #23
Steven T. Hatton wrote:
[snip]
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?


If you're looking for a quote from the standard, my copy says (3.9.6,
assuming I've copied it correctly):

"A class that has been declared but not defined, or an array of unknown
size or of incomplete element type, is an incompletely-defined object
type. Incompletely-defined object types and the void types are
incomplete types (3.9.1). Objects shall not be defined to have an
incomplete type."

3.9.7 then goes on to give examples and explain further. In fact, most
of that section seems relevant.

-- Pete
Jul 22 '05 #24
Steven T. Hatton wrote:
[snip]
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?


If you're looking for a quote from the standard, my copy says (3.9.6,
assuming I've copied it correctly):

"A class that has been declared but not defined, or an array of unknown
size or of incomplete element type, is an incompletely-defined object
type. Incompletely-defined object types and the void types are
incomplete types (3.9.1). Objects shall not be defined to have an
incomplete type."

3.9.7 then goes on to give examples and explain further. In fact, most
of that section seems relevant.

-- Pete
Jul 22 '05 #25
Howard wrote:

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Wc********************@speakeasy.net...
Steven T. Hatton wrote:
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?

struct A;

struct D {
A a;
};

struct A {};

I think that "formal rule" and "simplest terms" are mutually exclusive,
don't you? :-)


I was referring to the question, not the answer. :-)
Your compiler error itself is probably the simplest explanation of what
rule is violated.

I don't have the standard to see what the formal rule is, but didn't you
already mention it in another post in this conversation?

-Howard


That was actually helpful advice. I took the error " error: field `a' has
incomplete type" and searched the Standard for "incomplete".

I believe the reason is that the translation unit is processed sequentially
from 'top' to 'bottom'(I'm not sure where that is stated, or even if it is
stated.). So at the point where D::a is defined, A is an incomplete type.

3.9 #6 "A class that has been declared but not defined, or an array of
unknown size or of incomplete element type, is an incompletely-defined
object type.38) Incompletely-defined object types and the void types are
incomplete types (3.9.1). Objects shall not be defined to have an
incomplete type."

Footnote:"The size and layout of an instance of an incompletely-defined
object type is unknown."
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #26
Howard wrote:

"Steven T. Hatton" <su******@setidava.kushan.aa> wrote in message
news:Wc********************@speakeasy.net...
Steven T. Hatton wrote:
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?

struct A;

struct D {
A a;
};

struct A {};

I think that "formal rule" and "simplest terms" are mutually exclusive,
don't you? :-)


I was referring to the question, not the answer. :-)
Your compiler error itself is probably the simplest explanation of what
rule is violated.

I don't have the standard to see what the formal rule is, but didn't you
already mention it in another post in this conversation?

-Howard


That was actually helpful advice. I took the error " error: field `a' has
incomplete type" and searched the Standard for "incomplete".

I believe the reason is that the translation unit is processed sequentially
from 'top' to 'bottom'(I'm not sure where that is stated, or even if it is
stated.). So at the point where D::a is defined, A is an incomplete type.

3.9 #6 "A class that has been declared but not defined, or an array of
unknown size or of incomplete element type, is an incompletely-defined
object type.38) Incompletely-defined object types and the void types are
incomplete types (3.9.1). Objects shall not be defined to have an
incomplete type."

Footnote:"The size and layout of an instance of an incompletely-defined
object type is unknown."
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #27
Pete Vidler wrote:
Steven T. Hatton wrote:
[snip]
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?


If you're looking for a quote from the standard, my copy says (3.9.6,
assuming I've copied it correctly):

"A class that has been declared but not defined, or an array of unknown
size or of incomplete element type, is an incompletely-defined object
type. Incompletely-defined object types and the void types are
incomplete types (3.9.1). Objects shall not be defined to have an
incomplete type."

3.9.7 then goes on to give examples and explain further. In fact, most
of that section seems relevant.

-- Pete


I haven't had a chance to scour the Standard for the specification, but when
I looked in what I thought were the obvious places, I never found a
description of the order in which a translation unit is interpreted. Do
you happen to know where/if that is specified? I'm pretty sure it is
assumed to be 'top to bottom' single pass with no backtracking, but I don't
recall having read that, and I haven't found it while looking.
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #28
Pete Vidler wrote:
Steven T. Hatton wrote:
[snip]
In the simplest terms my question is this:
what's the formal rule that tells me this won't compile?


If you're looking for a quote from the standard, my copy says (3.9.6,
assuming I've copied it correctly):

"A class that has been declared but not defined, or an array of unknown
size or of incomplete element type, is an incompletely-defined object
type. Incompletely-defined object types and the void types are
incomplete types (3.9.1). Objects shall not be defined to have an
incomplete type."

3.9.7 then goes on to give examples and explain further. In fact, most
of that section seems relevant.

-- Pete


I haven't had a chance to scour the Standard for the specification, but when
I looked in what I thought were the obvious places, I never found a
description of the order in which a translation unit is interpreted. Do
you happen to know where/if that is specified? I'm pretty sure it is
assumed to be 'top to bottom' single pass with no backtracking, but I don't
recall having read that, and I haven't found it while looking.
--
p->m == (*p).m == p[0].m
http://www.kdevelop.org
http://www.suse.com
http://www.mozilla.org
Jul 22 '05 #29

This discussion thread is closed

Replies have been disabled for this discussion.

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.