Forward declaration allowed?

S

Steve

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...
 
J

John Harrison

Steve said:
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
 
M

Michael

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.' :)

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
 
S

Steve

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?"
 
S

Steve

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?"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,059
Latest member
cryptoseoagencies

Latest Threads

Top