when are declarations sufficent and when do we need definitions?

Discussion in 'C++' started by Jess, Jun 19, 2007.

  1. Jess

    Jess Guest

    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
     
    Jess, Jun 19, 2007
    #1
    1. Advertising

  2. Jess

    Zeppe Guest

    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
     
    Zeppe, Jun 19, 2007
    #2
    1. Advertising

  3. 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
     
    Victor Bazarov, Jun 19, 2007
    #3
  4. 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
     
    =?ISO-8859-1?Q?Erik_Wikstr=F6m?=, Jun 19, 2007
    #4
  5. Jess

    Jess Guest

    Thanks for all your answers!
    Jess
     
    Jess, Jun 19, 2007
    #5
  6. Jess

    Jess Guest

    There is another question I forgot to ask. :p

    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
     
    Jess, Jun 19, 2007
    #6
  7. Jess wrote:
    > There is another question I forgot to ask. :p
    >
    > 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
     
    Victor Bazarov, Jun 19, 2007
    #7
  8. Jess

    Jess Guest

    On Jun 19, 11:47 pm, "Victor Bazarov" <> wrote:
    > Jess wrote:
    > > There is another question I forgot to ask. :p

    >
    > > 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
     
    Jess, Jun 20, 2007
    #8
  9. Jess

    James Kanze Guest

    On Jun 19, 1:59 pm, 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
    > 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.8) 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:
    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
     
    James Kanze, Jun 20, 2007
    #9
  10. Jess

    Jess Guest

    Thanks a lot!

    On Jun 20, 9:53 pm, James Kanze <> wrote:
    > On Jun 19, 1:59 pm, 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
    > > 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
     
    Jess, Jun 20, 2007
    #10
  11. Jess

    James Kanze Guest

    On Jun 20, 2:47 pm, Jess <> wrote:
    > On Jun 20, 9:53 pm, James Kanze <> wrote:


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


    Yes. At least according to the standard.

    Note that the rule is NOT because it is a template. It's
    possible to write a template which allows instantiation over an
    incomplete type, or at least a class template which allows
    instantiation of the class definition (but not necessarily the
    member functions) over an incomplete type. But the standard
    doesn't require implementations to do this, even if most of the
    standard containers probably don't really need the complete type
    to instantiate the class (as opposed to member functions like
    the constructor).

    > For the typedef, is
    > it not enough if I have the following?


    > class A;


    > typedef A newAT;
    > typedef A* ap;


    > class A{..}


    For a typedef, yes. For a template, it depends on what's in the
    body of the template. For a template in the standard library
    (where you don't know what's in the body), no, because the
    standard says so, which means that an implementation might do
    something in the body which requires a complete type.

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


    Ouch. That's not easy to answer in the limited space of a
    posting, at least not without knowing how much you already know.
    As a first approximation, basically, an lvalue is an expression
    which refers to a specific object, like the name of a variable,
    or the results of dereferencing a pointer. An rvalue is an
    expression which is not an lvalue---it's just a value, without
    any underlying object. (This is very close to the absolute
    truth for built-in types. It gets a bit more complicated when
    class types are taken into consideration.) An lvalue-to-rvalue
    conversion occurs whenever you have an lvalue, and need an
    rvalue. For example:

    int x ;

    x = 3 ; // x is used as an lvalue...
    std::cout << x ; // x is used as an rvalue...

    In the above example, the 'x' is an lvalue. The output operator
    needs a simple rvalue. The conversion of the lvalue 'x' to an
    rvalue results in the value 3.

    In classical C, an lvalue designated an object, an rvalue
    didn't. In the above, x is an object, 3 isn't; in the
    assignment, we needed an lvalue on the left, since we need an
    object in which to put the 3. An expression like "3 = x"
    doesn't work.

    It's hard to find an example of code where you might require an
    lvalue to rvalue conversion with an incomplete type, however.
    Class types (which I'll talk about later) are a bit special, and
    the only non-class incomplete type is void. About the only
    example I can think of is:

    void* p1 ;
    void* p2 ;
    *p1 = *p2 ;

    The right hand side of an assignment is an rvalue, and since
    void is an incomplete type, the rvalue to lvalue conversion
    fails. (But there is another rule which says that the target
    type of a conversion must be complete, and that's enough to make
    the above assignment illegal.)

    With class types, it's almost impossible to talk reasonably
    about lvalue-to-rvalue conversions, because all operations on
    classes are defined as function calls, and a function call
    doesn't require an lvalue-to-rvalue conversion, ever: you can
    call a member function on an lvalue, you can bind an lvalue to a
    refernece, and in all other cases, you use the copy constructor
    to construct a new instance (and you can copy an lvalue). On
    the other hand, you can't call any member function (including
    the copy constructor or the assignment operator) unless the type
    is complete, which is what makes things like:
    class C ;
    C c1, c2 ;
    c1 = c2 ;
    illegal. (The distinction lvalue-rvalue is still relevant for
    class types, since you cannot bind an rvalue to a non-const
    reference.)

    --
    James Kanze (GABI Software, from CAI) email:
    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
     
    James Kanze, Jun 20, 2007
    #11
  12. Jess

    Jess Guest

    On Jun 21, 1:48 am, James Kanze <> wrote:
    > On Jun 20, 2:47 pm, Jess <> wrote:
    >
    > > On Jun 20, 9:53 pm, James Kanze <> wrote:
    > > > 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?

    >
    > Yes. At least according to the standard.
    >
    > Note that the rule is NOT because it is a template. It's
    > possible to write a template which allows instantiation over an
    > incomplete type, or at least a class template which allows
    > instantiation of the class definition (but not necessarily the
    > member functions) over an incomplete type. But the standard
    > doesn't require implementations to do this, even if most of the
    > standard containers probably don't really need the complete type
    > to instantiate the class (as opposed to member functions like
    > the constructor).
    >
    > > For the typedef, is
    > > it not enough if I have the following?
    > > class A;
    > > typedef A newAT;
    > > typedef A* ap;
    > > class A{..}

    >
    > For a typedef, yes. For a template, it depends on what's in the
    > body of the template. For a template in the standard library
    > (where you don't know what's in the body), no, because the
    > standard says so, which means that an implementation might do
    > something in the body which requires a complete type.
    >
    > > > 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"?

    >
    > Ouch. That's not easy to answer in the limited space of a
    > posting, at least not without knowing how much you already know.
    > As a first approximation, basically, an lvalue is an expression
    > which refers to a specific object, like the name of a variable,
    > or the results of dereferencing a pointer. An rvalue is an
    > expression which is not an lvalue---it's just a value, without
    > any underlying object. (This is very close to the absolute
    > truth for built-in types. It gets a bit more complicated when
    > class types are taken into consideration.) An lvalue-to-rvalue
    > conversion occurs whenever you have an lvalue, and need an
    > rvalue. For example:
    >
    > int x ;
    >
    > x = 3 ; // x is used as an lvalue...
    > std::cout << x ; // x is used as an rvalue...
    >
    > In the above example, the 'x' is an lvalue. The output operator
    > needs a simple rvalue. The conversion of the lvalue 'x' to an
    > rvalue results in the value 3.
    >
    > In classical C, an lvalue designated an object, an rvalue
    > didn't. In the above, x is an object, 3 isn't; in the
    > assignment, we needed an lvalue on the left, since we need an
    > object in which to put the 3. An expression like "3 = x"
    > doesn't work.
    >
    > It's hard to find an example of code where you might require an
    > lvalue to rvalue conversion with an incomplete type, however.
    > Class types (which I'll talk about later) are a bit special, and
    > the only non-class incomplete type is void. About the only
    > example I can think of is:
    >
    > void* p1 ;
    > void* p2 ;
    > *p1 = *p2 ;
    >
    > The right hand side of an assignment is an rvalue, and since
    > void is an incomplete type, the rvalue to lvalue conversion
    > fails. (But there is another rule which says that the target
    > type of a conversion must be complete, and that's enough to make
    > the above assignment illegal.)
    >
    > With class types, it's almost impossible to talk reasonably
    > about lvalue-to-rvalue conversions, because all operations on
    > classes are defined as function calls, and a function call
    > doesn't require an lvalue-to-rvalue conversion, ever: you can
    > call a member function on an lvalue, you can bind an lvalue to a
    > refernece, and in all other cases, you use the copy constructor
    > to construct a new instance (and you can copy an lvalue). On
    > the other hand, you can't call any member function (including
    > the copy constructor or the assignment operator) unless the type
    > is complete, which is what makes things like:
    > class C ;
    > C c1, c2 ;
    > c1 = c2 ;
    > illegal. (The distinction lvalue-rvalue is still relevant for
    > class types, since you cannot bind an rvalue to a non-const
    > reference.)


    Many thanks for the explanations! For class types, what are rvalues?
    Are they the (temporary) return values from functions?
    Jess
     
    Jess, Jun 21, 2007
    #12
  13. Jess

    James Kanze Guest

    On Jun 21, 3:06 pm, Jess <> wrote:
    > On Jun 21, 1:48 am, James Kanze <> wrote:


    > For class types, what are rvalues?


    Formally, the same rules as to whether an expression is an
    lvalue or an rvalue apply to both class types and non-class
    types. In practice, of course, most of the expressions aren't
    legal on a class type (except in the case of overloaded
    operators, and then the rules that apply are those of a function
    call, not of the operator). In fact, I think that the only way
    to get a class type rvalue is to call a function or if there is
    a conversion (explicit or implicit): a function call or the
    results of a conversion are lvalues if and only if the return
    type is a reference.

    Note that implicit conversions resulting from constructors which
    take a single argument or from user defined conversion operators
    are rvalues (except, in the latter case, if the conversion is to
    a reference). And don't forget that the standard considers
    something like "MyClass()" or "MyClass(a,b,c)" a conversion,
    even if it is hard to understand exactly what is being
    converted---at any rate, they are also rvalues.

    > Are they the (temporary) return values from functions?


    Yes. In many ways, temporary and rvalue are synonyms. The
    tendency is to use rvalue when we are concerned about
    constraints (e.g. on arguments to certain operators, or for
    binding to a reference), and temporary when we are concerned
    with the object itself, in particular its lifetime.

    --
    James Kanze (GABI Software, from CAI) email:
    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
     
    James Kanze, Jun 21, 2007
    #13
  14. Jess

    Jess Guest

    On Jun 22, 1:10 am, James Kanze <> wrote:
    > On Jun 21, 3:06 pm, Jess <> wrote:
    >
    > > On Jun 21, 1:48 am, James Kanze <> wrote:
    > > For class types, what are rvalues?

    >
    > Formally, the same rules as to whether an expression is an
    > lvalue or an rvalue apply to both class types and non-class
    > types. In practice, of course, most of the expressions aren't
    > legal on a class type (except in the case of overloaded
    > operators, and then the rules that apply are those of a function
    > call, not of the operator). In fact, I think that the only way
    > to get a class type rvalue is to call a function or if there is
    > a conversion (explicit or implicit): a function call or the
    > results of a conversion are lvalues if and only if the return
    > type is a reference.
    >
    > Note that implicit conversions resulting from constructors which
    > take a single argument or from user defined conversion operators
    > are rvalues (except, in the latter case, if the conversion is to
    > a reference). And don't forget that the standard considers
    > something like "MyClass()" or "MyClass(a,b,c)" a conversion,
    > even if it is hard to understand exactly what is being
    > converted---at any rate, they are also rvalues.
    >
    > > Are they the (temporary) return values from functions?

    >
    > Yes. In many ways, temporary and rvalue are synonyms. The
    > tendency is to use rvalue when we are concerned about
    > constraints (e.g. on arguments to certain operators, or for
    > binding to a reference), and temporary when we are concerned
    > with the object itself, in particular its lifetime.
    >
    > --
    > James Kanze (GABI Software, from CAI) email:
    > 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


    Thanks again! Then can I generalize it to say that we can't assign
    values to class-typed rvalues because the rvalues are temporaries and
    so compilers don't allow us to assign anything to temporaries?

    Jess
     
    Jess, Jun 23, 2007
    #14
  15. Jess

    James Kanze Guest

    On Jun 23, 2:14 pm, Jess <> wrote:
    > On Jun 22, 1:10 am, James Kanze <> wrote:

    [...]
    > > Yes. In many ways, temporary and rvalue are synonyms. The
    > > tendency is to use rvalue when we are concerned about
    > > constraints (e.g. on arguments to certain operators, or for
    > > binding to a reference), and temporary when we are concerned
    > > with the object itself, in particular its lifetime.


    > Thanks again! Then can I generalize it to say that we can't assign
    > values to class-typed rvalues because the rvalues are temporaries and
    > so compilers don't allow us to assign anything to temporaries?


    No. In fact, you can assign to a class type temporary. All of
    the rules concerning where lvalues are required or not concern
    the built-in operators, and a class type doesn't have any
    built-in operators. User defined operators obey the rules for
    function calls (since that's what they are), and you are allowed
    to call a member function on an rvalue/temporary. So, given
    something like:

    f() = x ;

    This is legal if f returns a reference (because a reference is
    always an lvalue), or if f returns a class type, because
    operator= is a member function, and you can call member
    fucntions on class types.

    (Of course, the types have to match. And if the return type of
    f is const, then you can't call non-const functions on it, and
    since operator= is always a non-const function, that prevents
    it.)

    --
    James Kanze (Gabi Software) email:
    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
     
    James Kanze, Jun 23, 2007
    #15
  16. Jess

    Jess Guest

    On Jun 24, 4:32 am, James Kanze <> wrote:
    > On Jun 23, 2:14 pm, Jess <> wrote:
    >
    > > On Jun 22, 1:10 am, James Kanze <> wrote:

    > [...]
    > > > Yes. In many ways, temporary and rvalue are synonyms. The
    > > > tendency is to use rvalue when we are concerned about
    > > > constraints (e.g. on arguments to certain operators, or for
    > > > binding to a reference), and temporary when we are concerned
    > > > with the object itself, in particular its lifetime.

    > > Thanks again! Then can I generalize it to say that we can't assign
    > > values to class-typed rvalues because the rvalues are temporaries and
    > > so compilers don't allow us to assign anything to temporaries?

    >
    > No. In fact, you can assign to a class type temporary. All of
    > the rules concerning where lvalues are required or not concern
    > the built-in operators, and a class type doesn't have any
    > built-in operators. User defined operators obey the rules for
    > function calls (since that's what they are), and you are allowed
    > to call a member function on an rvalue/temporary. So, given
    > something like:
    >
    > f() = x ;
    >
    > This is legal if f returns a reference (because a reference is
    > always an lvalue), or if f returns a class type, because
    > operator= is a member function, and you can call member
    > fucntions on class types.
    >
    > (Of course, the types have to match. And if the return type of
    > f is const, then you can't call non-const functions on it, and
    > since operator= is always a non-const function, that prevents
    > it.)
    >
    > --
    > James Kanze (Gabi Software) email:
    > 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


    Thanks for clarifying the matter!
    Jess
     
    Jess, Jun 25, 2007
    #16
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Rikard Land
    Replies:
    0
    Views:
    353
    Rikard Land
    Oct 19, 2004
  2. Steven T. Hatton

    Declarations and Definitions in One Header

    Steven T. Hatton, Apr 25, 2004, in forum: C++
    Replies:
    4
    Views:
    338
    Steven T. Hatton
    Apr 25, 2004
  3. Chris Gordon-Smith

    Declarations and Definitions: Grammar

    Chris Gordon-Smith, Oct 3, 2004, in forum: C++
    Replies:
    2
    Views:
    384
    Gary Labowitz
    Oct 3, 2004
  4. aaragon
    Replies:
    14
    Views:
    414
  5. panku

    declarations and definitions

    panku, Feb 1, 2011, in forum: C Programming
    Replies:
    6
    Views:
    307
    David Thompson
    Feb 11, 2011
Loading...

Share This Page