Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > when are declarations sufficent and when do we need definitions?

Reply
Thread Tools

when are declarations sufficent and when do we need definitions?

 
 
Jess
Guest
Posts: n/a
 
      06-19-2007
Hello,

Sometimes declarations are all what we need when we define/declare
classes (or functions?), but sometimes we need definitions. I learned
that if we define a class (B) that has an object (a_obj) of a class
type (A), then we need to define A as well, but if B has a pointer to
A, then we only need to forward declare A. I was told this is because
the compiler needs to see the implemenation of A when allocating
memory for a_obj. However, I think compilers won't allocate any
memory until we create an object of class B. Therefore, if I have
a .cpp file

class A;

class B{
A a_obj;
};

then it seems ok to forward declare A, because there's no object of
class B created. So in this case, why do I still have to define A (or
include it's header file)?

Similarly, we can forward declare A if we only declare a function like

A f(A a);

but we need A's implemenation when we define "f"

A f(A a){...}

If my .cpp file only has f's definition without any program that calls
"f", then shouldn't it be perfectly safe to forward declare A?

I guess my general question is when can we use declarations without
definitions?

Another question about forward declaration is that why do we use

class A;

instead of

extern class A;

I think the latter says A is a class defined somewhere else.

Thanks a lot,
Jess

 
Reply With Quote
 
 
 
 
Zeppe
Guest
Posts: n/a
 
      06-19-2007
Jess wrote:
> Hello,
>
> Sometimes declarations are all what we need when we define/declare
> classes (or functions?), but sometimes we need definitions. I learned
> that if we define a class (B) that has an object (a_obj) of a class
> type (A), then we need to define A as well, but if B has a pointer to
> A, then we only need to forward declare A. I was told this is because
> the compiler needs to see the implemenation of A when allocating
> memory for a_obj.


No, it is not related to allocation. It's related to the semantics. The
rule of thumb is: "when the program doesn't need to know anything about
the class, the forward declaration suffices". That is, if you merely
have a pointer (which is an address of memory) to a class, there is no
need to know anything about the class itself. On the other side, if you
want to use methods of the class, or if you have a member that is not a
pointer, additional information related to the class (such the class
dimension or its members) are required, and the definition is needed.

Regards,

Zeppe
 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      06-19-2007
Jess wrote:
> Sometimes declarations are all what we need when we define/declare
> classes (or functions?), but sometimes we need definitions. I learned
> that if we define a class (B) that has an object (a_obj) of a class
> type (A), then we need to define A as well, but if B has a pointer to


...or a reference to..

> A, then we only need to forward declare A. I was told this is because
> the compiler needs to see the implemenation of A when allocating
> memory for a_obj. However, I think compilers won't allocate any
> memory until we create an object of class B. Therefore, if I have
> a .cpp file
>
> class A;
>
> class B{
> A a_obj;
> };
>
> then it seems ok to forward declare A, because there's no object of
> class B created. So in this case, why do I still have to define A (or
> include it's header file)?


The compiler needs to calculate the size of a 'B' object. For that it
needs to know what the size of an 'A' object is. It cannot know the
size of an 'A' object without knowing what it consists of.

> Similarly, we can forward declare A if we only declare a function like
>
> A f(A a);
>
> but we need A's implemenation when we define "f"
>
> A f(A a){...}
>
> If my .cpp file only has f's definition without any program that calls
> "f", then shouldn't it be perfectly safe to forward declare A?


The standard does not prohibit from incomplete types used in function
declarations, but in definitions you cannot use incomplete types. There
is no special provisions for the functions that aren't called within
your own code. The code for them has to be generated, so the parameters
have to have complete types.

>
> I guess my general question is when can we use declarations without
> definitions?


What do you mean by "use"?

>
> Another question about forward declaration is that why do we use
>
> class A;
>
> instead of
>
> extern class A;
>
> I think the latter says A is a class defined somewhere else.


"extern" is not allowed with a class declaration. Only with objects
and functions.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask


 
Reply With Quote
 
=?ISO-8859-1?Q?Erik_Wikstr=F6m?=
Guest
Posts: n/a
 
      06-19-2007
On 2007-06-19 13:59, Jess wrote:
> Hello,
>
> Sometimes declarations are all what we need when we define/declare
> classes (or functions?), but sometimes we need definitions. I learned
> that if we define a class (B) that has an object (a_obj) of a class
> type (A), then we need to define A as well, but if B has a pointer to
> A, then we only need to forward declare A. I was told this is because
> the compiler needs to see the implemenation of A when allocating
> memory for a_obj. However, I think compilers won't allocate any
> memory until we create an object of class B. Therefore, if I have
> a .cpp file
>
> class A;
>
> class B{
> A a_obj;
> };
>
> then it seems ok to forward declare A, because there's no object of
> class B created. So in this case, why do I still have to define A (or
> include it's header file)?


It's true that the compiler will not allocate memory for an object of
type B until you create such an object. But the compiler will need to
know how A looks like when you define B since the definition of B should
contain all the compiler needs to know to be able to create an object of
type B. But if the compiler does not know what A is in the definition of
B, how can it know what B is?

> Similarly, we can forward declare A if we only declare a function like
>
> A f(A a);
>
> but we need A's implemenation when we define "f"
>
> A f(A a){...}
>
> If my .cpp file only has f's definition without any program that calls
> "f", then shouldn't it be perfectly safe to forward declare A?


Once again, the definition should contain all information the compiler
need, in this case it must know the size of A so that it can generate
the code for f(). If you then don't use f() a smart compiler might be
able get rid of f() as an optimization, but the standard does not
require it, so a not-so-smart compiler must be able to compile the code
also.

> I guess my general question is when can we use declarations without
> definitions?


Usually it's a question of size, for many things (like a member of a
class) the compiler needs to know the size. As long as you use pointers
of references the compiler does not need to know more since the sizes of
pointers and references are known. If you in some way try to use a
pointer/reference (like calling a member-function) you'll need the
definition.

> Another question about forward declaration is that why do we use
>
> class A;
>
> instead of
>
> extern class A;


extern is used when you tell the compiler about an existing variable
that was not defined in the current compilation unit. So when you write
something like

extern A myA;

you tell the compiler that there exists a variable of type A called myA.
In the case of forward declarations you use the word "class" (notice
that I didn't use "class" in the above extern declaration) to tell the
compiler that you are talking about a type and not a variable. While one
could have used

extern class A;

as forward declarations it's not needed since the compiler does not
particularly care where the type is defined, as long as it is somewhere.
Notice also that this would be a new kind of use of the word extern,
which means that the definition is external to the compilation unit,
since in most cases a forward declaration is followed by the real
declaration later in the file or by some included file (in other words
the forward declaration and definition is in the same compilation unit),
like this:

class B;

class A {
B* parentPtr;
/* ... */
};

class B {
A child;
/* ... */
};

--
Erik Wikström
 
Reply With Quote
 
Jess
Guest
Posts: n/a
 
      06-19-2007
Thanks for all your answers!
Jess

 
Reply With Quote
 
Jess
Guest
Posts: n/a
 
      06-19-2007
There is another question I forgot to ask.

In Effective C++, the author said to decouple declaration and
definitions, we can have two header files for each class: one for
declarations and one for definitions. I'm imagining how they'd look
like and how to use them. I think for the declaration header, perhaps
I can have

//decl.h
class A{
public:
void f();
A();
};

Then in its definition header, it can look like

//def.h
#include "decl.h"
void A::f(){...}
A::A(){...}

Somehow, I don't think this is quite right, because the second one
doesn't look like a header file; it looks like a .cpp file.

There are also two questions that I'm thinking
a. if I need to define some data members in A, then how can I declare
them without showing them in decl.h?
b. for a client of class A, is it "decl.h" that it should #include?

Thanks,
Jess

 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      06-19-2007
Jess wrote:
> There is another question I forgot to ask.
>
> In Effective C++, the author said to decouple declaration and
> definitions, we can have two header files


<should be>
...two files..
</should be>

Can you find the location in the book where the author says that?

> for each class: one for
> declarations and one for definitions. I'm imagining how they'd look
> like and how to use them. I think for the declaration header, perhaps
> I can have
>
> //decl.h
> class A{
> public:
> void f();
> A();
> };
>
> Then in its definition header,


<should be>
...in its implementation module..
</should be>

> it can look like
>
> //def.h
> #include "decl.h"
> void A::f(){...}
> A::A(){...}
>
> Somehow, I don't think this is quite right, because the second one
> doesn't look like a header file; it looks like a .cpp file.


Right.

>
> There are also two questions that I'm thinking
> a. if I need to define some data members in A, then how can I declare
> them without showing them in decl.h?


"Showing them"? What do you mean by that?

> b. for a client of class A, is it "decl.h" that it should #include?


Yes, I would think so.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask


 
Reply With Quote
 
Jess
Guest
Posts: n/a
 
      06-20-2007
On Jun 19, 11:47 pm, "Victor Bazarov" <(E-Mail Removed)> wrote:
> Jess wrote:
> > There is another question I forgot to ask.

>
> > In Effective C++, the author said to decouple declaration and
> > definitions, we can have two header files

>
> <should be>
> ..two files..
> </should be>
>
> Can you find the location in the book where the author says that?


On p144, first paragraph. I'm wondering if the author means we should
use PIMPL strategy. However, he seems to use this item as a general
suggestion.

>
> > for each class: one for
> > declarations and one for definitions. I'm imagining how they'd look
> > like and how to use them. I think for the declaration header, perhaps
> > I can have

>
> > //decl.h
> > class A{
> > public:
> > void f();
> > A();
> > };

>
> > Then in its definition header,

>
> <should be>
> ..in its implementation module..
> </should be>


Do you mean it should be in .cpp file?

>
> > it can look like

>
> > //def.h
> > #include "decl.h"
> > void A::f(){...}
> > A::A(){...}

>
> > Somehow, I don't think this is quite right, because the second one
> > doesn't look like a header file; it looks like a .cpp file.

>
> Right.


The author says we need a pair of header files, rather than .h + .cpp
files...

>
>
> > There are also two questions that I'm thinking
> > a. if I need to define some data members in A, then how can I declare
> > them without showing them in decl.h?

>
> "Showing them"? What do you mean by that?


I mean if we only declare a class, then it seems we shouldn't include
implementation detail, hence the data member should be hidden. If the
header file "decl.h" doesn't mention any data member, how can I
secretly define data members in the corresponding implementation file?
I'm now wondering if "decl.h" should only include a declaration of a
class like

class A;
void A::f();

Thanks,
Jess

 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      06-20-2007
On Jun 19, 1:59 pm, Jess <(E-Mail Removed)> wrote:

> Sometimes declarations are all what we need when we define/declare
> classes (or functions?), but sometimes we need definitions. I learned
> that if we define a class (B) that has an object (a_obj) of a class
> type (A), then we need to define A as well, but if B has a pointer to
> A, then we only need to forward declare A. I was told this is because
> the compiler needs to see the implemenation of A when allocating
> memory for a_obj. However, I think compilers won't allocate any
> memory until we create an object of class B. Therefore, if I have
> a .cpp file


> class A;


> class B{
> A a_obj;
> };


> then it seems ok to forward declare A, because there's no object of
> class B created. So in this case, why do I still have to define A (or
> include it's header file)?


The need for a definition isn't only related to size; you need a
class definition any time the compiler needs to know more than
just "it's a class". That means anything concerning layout, for
example, which is why you need it here. It also means anytime
you use something declared in the class: a function, a member or
even a typedef. And---because the standard says so---it means
anytime you instantiate a template from the standard library on
the class.

> Similarly, we can forward declare A if we only declare a function like


> A f(A a);


> but we need A's implemenation when we define "f"


> A f(A a){...}


Yes, because the function itself has to know how to copy,
construct and destruct the type.

> If my .cpp file only has f's definition without any program that calls
> "f", then shouldn't it be perfectly safe to forward declare A?


How's the compiler going to generate the destructor of the
argument, or the copy constructor of the return value?

> I guess my general question is when can we use declarations without
> definitions?


There's a list in the standard (§3.2/4):

A class type T must be complete if:

-- an object of type T is defined (3.1), or

-- a non-static class data member of type T is declared
(9.2), or

-- T is used as the object type or array element type
in a new-expression (5.3.4), or

-- an lvalue-to-rvalue conversion is applied to an
lvalue referring to an object of type T (4.1), or

-- an expression is converted (either implicitly or
explicitly) to type T (clause 4, 5.2.3, 5.2.7,
5.2.9, 5.4), or

-- an expression that is not a null pointer constant,
and has type other than void *, is converted to the
type pointer to T or reference to T using an
implicit conversion (clause 4), a dynamic_cast
(5.2.7) or a static_cast (5.2.9), or

-- a class member access operator is applied to an
expression of type T (5.2.5), or

-- the typeid operator (5.2. or the sizeof operator
(5.3.3) is applied to an operand of type T, or

-- a function with a return type or argument type of
type T is defined (3.1) or called (5.2.2), or

-- a class with a base class of type T is defined (10),
or

-- an lvalue of type T is assigned to (5.17).

This is part of a note, and so is non-normative, but I assume
that it is an accurate synthesis of rules that appear spread out
elsewhere throughout the standard.

> Another question about forward declaration is that why do we use


> class A;


> instead of


> extern class A;


> I think the latter says A is a class defined somewhere else.


What does "extern" mean exactly? It means that the name being
defined has external linkage. And the name of a class always
has external linkage (except in block scope). So the extern
here would be superflulous. And if I wrote:
extern class A* pA ;
which name has external linkage: A or pA? (Note that this
statement *is* legal, and it is pA which has external linkage,
and isn't defined; A always has external linkage, and it is the
syntax of what follows which determines whether it is defined or
not.)

A more formal reason is that extern is part of the declaration
specifier, and applies to all of the names specified in the
declarator. When I write "class A;", there is no declarator, so
extern (like other storage class specifiers) is illegal.

The rules aren't completely coherent---in fact, they're not
really very coherent at all. But in this case, they sort of
make sense. Locally, at least, in that allowing extern here
would cause too many other problems elsewhere.

In another language, one might have:

{define|declare} <linkage-spec] definition-or-declaration ;

with everything very explicit. That other language wouldn't
have been based on C, however.

--
James Kanze (GABI Software, from CAI) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

 
Reply With Quote
 
Jess
Guest
Posts: n/a
 
      06-20-2007
Thanks a lot!

On Jun 20, 9:53 pm, James Kanze <(E-Mail Removed)> wrote:
> On Jun 19, 1:59 pm, Jess <(E-Mail Removed)> wrote:
>
>
>
> > Sometimes declarations are all what we need when we define/declare
> > classes (or functions?), but sometimes we need definitions. I learned
> > that if we define a class (B) that has an object (a_obj) of a class
> > type (A), then we need to define A as well, but if B has a pointer to
> > A, then we only need to forward declare A. I was told this is because
> > the compiler needs to see the implemenation of A when allocating
> > memory for a_obj. However, I think compilers won't allocate any
> > memory until we create an object of class B. Therefore, if I have
> > a .cpp file
> > class A;
> > class B{
> > A a_obj;
> > };
> > then it seems ok to forward declare A, because there's no object of
> > class B created. So in this case, why do I still have to define A (or
> > include it's header file)?

>
> The need for a definition isn't only related to size; you need a
> class definition any time the compiler needs to know more than
> just "it's a class". That means anything concerning layout, for
> example, which is why you need it here. It also means anytime
> you use something declared in the class: a function, a member or
> even a typedef. And---because the standard says so---it means
> anytime you instantiate a template from the standard library on
> the class.


So if I instantiate a template, say vector, using a class A, then I
need to define A instead of forward declaring A? For the typedef, is
it not enough if I have the following?

class A;

typedef A newAT;
typedef A* ap;

class A{..}


> There's a list in the standard (§3.2/4):
>
> A class type T must be complete if:
>
> -- an object of type T is defined (3.1), or
>
> -- a non-static class data member of type T is declared
> (9.2), or
>
> -- T is used as the object type or array element type
> in a new-expression (5.3.4), or
>
> -- an lvalue-to-rvalue conversion is applied to an
> lvalue referring to an object of type T (4.1), or


Can you please tell me what is "lvalue-to-rvalue conversion"?

Thanks,
Jess

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
mixed declarations and code (and size_t)? Zach C Programming 7 11-15-2010 04:39 PM
Do base class declarations need to be fully namespace-qualified? sunrise@familjenjonsson.org C++ 0 03-17-2009 07:16 PM
Need help with declarations (simple question) twoeyedhuman1111 C++ 8 08-08-2005 02:55 AM
[VHDL] Comparing entity and component declarations M.D. van de Burgwal VHDL 3 10-07-2004 08:58 AM
NEED HELP with forward declarations Alan Lee C++ 5 04-05-2004 01:03 PM



Advertisments