By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,412 Members | 1,009 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,412 IT Pros & Developers. It's quick & easy.

Forward declaration allowed?

P: n/a
Hi,

I always though to return an instance of a class by value, it had to be
defined - i.e. forward declaration isn't good enough?

Consider the following code snippet:

class RGBA;

class Colour
{
public:
virtual RGBA ToRGBA() const = 0; // [1]
};

class RedComponent;

class RGBA : public Colour
{
public:
RGBA( double r, double g, double b, double a = 1.0 );
virtual RGBA ToRGBA() const;
RedComponent GetRed() const;
};
class HSV : public Colour
{
public:
HSV( double h, double s, double v, double a = 1.0 );
virtual RGBA ToRGBA() const;
};

int main()
{
RGBA red( 1.0, 0.0, 0.0 );
HSV papayaWhip( 37.0, 0.16, 1.0 );
RGBA c = papayaWhip.ToRGBA();
c.Red(); // << [2]
return 0;
}

Colour::ToRGBA can be declared to return an RGBA by value even though it is
only forward declared?

I understand the error at [2] in the call to c.Red() - RedComponent is
incomplete. But this is the error I would have expected at [1] - which
compiles cleanly in Visual Studio 2005 and gcc version 4.0.1 (Apple
Computer, Inc. build 5363)

Is it because Colour::ToRGBA is only declared here, and RGBA must be fully
defined at it's definition, but only requires a declaration elsewhere? Or
is this something special to do with pure virtuals?

I was always taught that a forward declaration is good enough for a pointer
or reference use, but a by-value use required the full class's definition?

Thanks for any insights...

--
Regards,
Steve.

Feb 22 '07 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Steve wrote:
Hi,

I always though to return an instance of a class by value, it had to be
defined - i.e. forward declaration isn't good enough?
Forward declaration is good enough for this case.
>
Consider the following code snippet:

class RGBA;

class Colour
{
public:
virtual RGBA ToRGBA() const = 0; // [1]
};
[snip]

I think your confusion is that

virtual RGBA ToRGBA() const = 0; // [1]

is not a 'by-value use'. It's only a declaration. If you actually called
ToRGBA that would be a by-value use.

>
Thanks for any insights...
john
Feb 22 '07 #2

P: n/a
On Feb 22, 10:51 am, Steve <r...@127.0.0.1wrote:
I always though to return an instance of a class by value, it had to be
defined - i.e. forward declaration isn't good enough?
This is a common misperception, even among regulars to this group.
Consider the following code snippet:

class RGBA;

class Colour
{
public:
virtual RGBA ToRGBA() const = 0; // [1]
};
This is perfectly legitimate, with the possible exception of the 'u'
in 'Color.' :)

<snip>
Colour::ToRGBA can be declared to return an RGBA by value even though it is
only forward declared?
Yes.

You must, however, have the full definition at the call site. So for
example:

// newfile.cpp
#include "Colour.h" /* forward declaration of RGBA */
#include "MyColour.h" /* class implementing Colour, with forward
declaration of RGBA */
int main() {
MyColor mc;
RGBA x = mc.ToRGBA(); /* <- Error, RGBA is not defined!!!! */
}
Is it because Colour::ToRGBA is only declared here, and RGBA must be fully
defined at it's definition, but only requires a declaration elsewhere? Or
is this something special to do with pure virtuals?
The former. You need the full definition 1) in the definition of
ToRGBA and 2) at any point where you call ToRGBA.
I was always taught that a forward declaration is good enough for a pointer
or reference use, but a by-value use required the full class's definition?
You need the full definition of a class C only in a couple cases:
1) You inherit from C
2) You have a member variable of type C
3) Your implementation uses an object of type C or uses the internals
of type C

This is the difference between using C "in size" (1 & 2 & 3) or "in
name only" (pointers, references, and declarations of function
parameters).

The compiler needs to know the size of type C if you inherit, so it
can calculate the size of your inherited class. It needs to know the
size of type C if you have a member variable of type C, so it can
calculate the size of the class (note that this doesn't apply if your
member variable is a pointer or a reference), and of course, where
your implementation uses an object of type C (automatic or with new),
or uses C.xyz. It also needs the size when you call a function with a
parameter of type C or a return value of type C, but that requirement
is only at the call site, not at the declaration.

Michael

Feb 22 '07 #3

P: n/a
On 22/2/07 19:39, in article Ej*******************@newsfe4-gui.ntli.net,
"John Harrison" <jo*************@hotmail.comwrote:
I think your confusion is that

virtual RGBA ToRGBA() const = 0; // [1]

is not a 'by-value use'. It's only a declaration. If you actually called
ToRGBA that would be a by-value use.
Yes, that is the evidence I was seeing, but couldn't quite understand it
fully.

Thanks very much for your quick reply.

--
Regards,
Steve

"...which means he created the heaven and the earth... in the DARK! How good
is that?"

Feb 22 '07 #4

P: n/a
On 22/2/07 19:57, in article
11**********************@t69g2000cwt.googlegroups. com, "Michael"
<mc******@aol.comwrote:
This is perfectly legitimate, with the possible exception of the 'u'
in 'Color.' :)
Have you a licence in correcting spelling non-mistakes? ;-)
<snipped a good explanation>

You need the full definition of a class C only in a couple cases:
1) You inherit from C
2) You have a member variable of type C
3) Your implementation uses an object of type C or uses the internals
of type C

This is the difference between using C "in size" (1 & 2 & 3) or "in
name only" (pointers, references, and declarations of function
parameters).

The compiler needs to know the size of type C if you inherit, so it
can calculate the size of your inherited class. It needs to know the
size of type C if you have a member variable of type C, so it can
calculate the size of the class (note that this doesn't apply if your
member variable is a pointer or a reference), and of course, where
your implementation uses an object of type C (automatic or with new),
or uses C.xyz. It also needs the size when you call a function with a
parameter of type C or a return value of type C, but that requirement
is only at the call site, not at the declaration.

Michael
Got it! I think actually I was confusing this usage with case 2.

Thanks very much for your explanation.

--
Regards,
Steve

"...which means he created the heaven and the earth... in the DARK! How good
is that?"

Feb 22 '07 #5

This discussion thread is closed

Replies have been disabled for this discussion.