Classes and Default Constructors

Discussion in 'C++' started by gordon.is.a.moron@gmail.com, Jan 11, 2009.

  1. Guest

    Hello,

    I have a few questions regarding classes in C++. First of all I have
    two classes. I have a default constructor that assigns default values:

    //class D.h
    class D
    {
    public:
    D(int id = 0, int sn =0);

    }


    I want to associate Class D with Class E:

    //class E.h
    class E
    {
    private:
    D instance_;
    }

    //class E.cpp
    {
    void E::SendData()
    {
    D instance_(50.12);
    }
    }

    However, the D instance_ delcaration calls the default constructor
    with default values. So as well as calling the constructor in a
    function in class E, the default constructor is called first with
    default values. What is the correct way of associating an instance
    with the other object without invoking the default constructor? The
    isue is I can't really set those parameters in the declaration, and
    I'm not sure I really should anyway, it doesn't seem correct.

    And in a related question, I'm not entirely clear when you would call
    D instance_(50,12) and D *instance_ = new D(50,12). I was doing this
    initially as I thought using pointers would be more efficient over
    references, but I'm not sure this is true. As far as I can gather I
    should use references as much as possible and only use pointers when I
    need to change what I'm pointing to, since I can't "move" a reference.
    And also I would guess when I want to create an indeterminate number
    of objects at runtime dynamically, which would presumably force me to
    use pointers as this is what new returns in C++ when creating objects
    of classes.

    Regards,

    Gordy.
    , Jan 11, 2009
    #1
    1. Advertising

  2. James Kanze Guest

    On Jan 11, 10:30 am, wrote:

    > I have a few questions regarding classes in C++. First of all
    > I have two classes. I have a default constructor that assigns
    > default values:


    > //class D.h
    > class D
    > {
    > public:
    > D(int id = 0, int sn =0);
    > }


    You're missing a ';'. It's generally preferable to post
    compilable code.

    > I want to associate Class D with Class E:


    What do you mean by "associate"? There are lots of different
    types of association.

    > //class E.h
    > class E
    > {
    > private:
    > D instance_;
    > }


    Ditto.

    > //class E.cpp
    > {
    > void E::SendData()
    > {
    > D instance_(50.12);
    > }
    > }


    And I don't understand this at all. What are the outer braces
    doing? And more importantly, what is void E::SendData(). If
    it's a member function, then instance_ is a local variable, and
    the fact that it is in a member function of E is largely
    irrelevant.

    > However, the D instance_ delcaration calls the default
    > constructor with default values.


    No it doesn't. It calls D::D( 50, 0 ), only using the default
    value for the missing second argument. (It also truncates the
    floating point first argument. Perhaps you meant to write:

    D instance_( 50, 12 ) ;

    In that case, it will call D::D( 50, 12 ).

    > So as well as calling the constructor in a function in class
    > E, the default constructor is called first with default
    > values.


    If you specify values in the definition, the compiler will call
    the corresponding constructor.

    > What is the correct way of associating an instance
    > with the other object without invoking the default
    > constructor?


    What do you mean by "associating"? If the object is a base
    class or member, you use the initializer sequence in the
    constructor. Otherwise, you provide initializers in the
    statement which creates the object; in the definition or the new
    expression.

    > The isue is I can't really set those parameters in the
    > declaration, and I'm not sure I really should anyway, it
    > doesn't seem correct.


    Why can't use set them in the definition? If you don't know
    them at that moment, perhaps the definition is appearing too
    early.

    > And in a related question, I'm not entirely clear when you
    > would call D instance_(50,12) and D *instance_ = new D(50,12).


    You use the first when you want static or automatic lifetime,
    the second when you want dynamic lifetime. If the object has
    copy semantics, it's generally preferable to stick to automatic
    lifetime, copying it as necessary. At least until the profiler
    tells you otherwise.

    > I was doing this initially as I thought using pointers would
    > be more efficient over references, but I'm not sure this is
    > true.


    Given that all compilers I know implement references as
    pointers, any differences are likely to be slight, favoring
    references (since the compiler might be able to optimize a
    little better knowing that the value can't be null).

    But how is there relevant to any of the above? Nothing you've
    posted involves references in the least.

    > As far as I can gather I should use references as much as
    > possible and only use pointers when I need to change what I'm
    > pointing to, since I can't "move" a reference.


    That's part of what is probably the most frequent rule. Another
    part is that you use pointers if you need a possible null
    pointer. And most coding guidelines seem to recommend pointers
    when changing ownership; for whatever reasons, most people don't
    seem to like having to do "delete &someReference". But in the
    end, it's largely a question of local coding conventions, except
    in the cases where references don't work.

    > And also I would guess when I want to create an indeterminate
    > number of objects at runtime dynamically, which would
    > presumably force me to use pointers as this is what new
    > returns in C++ when creating objects of classes.


    It's possible to do this with references, as well, but probably
    not very idiomatic. Most of the time, you'll either want a null
    pointer (to indicate a dead end in the navigation branch), or
    you'll need to reseat the pointers (since if there are no
    dead-ends, the graph must contain cycles).

    --
    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, Jan 11, 2009
    #2
    1. Advertising

  3. Guest

    On Jan 12, 2:57 am, "Daniel T." <> wrote:

    <helpful ctor sequence snipped>

    >
    > When E::SendData is called, you are declaring a new object named
    > 'instance_' and constructing it with the values provided (I'm assuming
    > here that you meant to type "50,12" not "50.12".) This new object is not
    > associated with the member-variable E::instance_ in any way.
    >
    > > What is the correct way of associating an instance
    > > with the other object without invoking the default constructor? The
    > > isue is I can't really set those parameters in the declaration, and
    > > I'm not sure I really should anyway, it doesn't seem correct.

    >
    > Since a D object must be constructed when the E object gets constructed,
    > then the most obvious solution is to provide the parameters in the E
    > object's constructor, like this:
    >
    > class E {
    >    D instance_;
    > public:
    >    E():instance_(50, 12) { }
    >    void SendData() {
    >       // use 'instance_' here.
    >    }
    >
    > };
    >
    > If you don't know what the values will be until runtime (i.e., if you
    > are using variables for the values and the variables aren't set until
    > after the programs been running for a bit,) then you need to use new to
    > avoid the default construction, like this:
    >
    > class E {
    >    D* instance_;
    > public:
    >    E(): instance_(0) { }
    >    ~E() { delete instance_ }
    >    E(const E& o): instance_(0) {
    >       if (o.instance_)
    >          instance_ = new D(*o.instance_);
    >    }
    >    void operator=(const E& o) {
    >       E tmp(o);
    >       swap(tmp.instance_, instance_);
    >    }
    >    void SendData(int x, int y) {
    >       delete instance_;
    >       instance_ = new D(x, y);
    >       // use 'instance_' here.
    >    }
    >
    > };
    >
    > Yes, all that extra code is necessary if you want copy construction and
    > assignment to work properly.
    >


    I may have to do this. The "real code" is actually creating a custom
    event (class) in a third party library. The first parameter is an
    event type rather than an int (the second is an int ID for the event
    table). I probably should've left that in, but I just tried to
    simplify it. There are various ways to do it, but using the suggestion
    below (i.e. no copy ctor) doesn't work at the moment.

    > Unless you have a very powerful reason to avoid the default
    > construction, it would be easier to go ahead and let the default
    > construction happen. Then the code would look like this:
    >


    I don't really, the below code is what I was intending. I just thought
    it was inefficient to call the default ctor when I didn't need to.

    > class E {
    >    D instance_;
    > public:
    >    void SendData(int x, int y) {
    >       instance_ = D(x, y);
    >    }
    >
    > };
    >
    > Note in the above code how I assigned to instance_ rather than declaring
    > a variable named instance_ as you did in your code.
    >


    Good point. I have discussed this with users of the library. They
    reckoned that it's unusual to associate the event class with the
    client classes as the event shouldn't be modified after being fired.
    However, I though an association (in the OO sense) applied to one
    object calling another on it's behalf. I call set methods after
    creation in one class (i.e. I populate data in the event class in
    sendata) and I will eventually get that data using an accessor in the
    other client class that the event is being fired at. This is where I
    got the idea of the associations. I would guess that the event should
    not be associated and the event system should handle this. I suppose
    the point of en event system it that it is de-coupled to an extent. I
    know that is OO rather than C++, but I thought I'd throw it in...

    > > And in a related question, I'm not entirely clear when you would call
    > > D instance_(50,12) and D *instance_ = new D(50,12). I was doing this
    > > initially as I thought using pointers would be more efficient over
    > > references, but I'm not sure this is true.


    My mistake, yes you're right that should be 50,12 not 50.12.
    >
    > Your example doesn't compare references to pointers. 'D instance_(50,
    > 12)' defines an object, not a reference to an object. I suggest you
    > avoid using new whenever you can. It makes the code much easer to
    > understand and write in most cases.
    >


    Ah, thanks. I think you have cleared up a misunderstanding I had for a
    while. That certainly makes it much more clear. In Java creating an
    object returns what they refer to as a refernce (though I've since
    read that it is actually more like a pointer). So I was under the
    impression a reference was returned in my example, and a pointer would
    be returned using new. Obviously the former is incorrect.

    > > As far as I can gather I
    > > should use references as much as possible and only use pointers when I
    > > need to change what I'm pointing to, since I can't "move" a reference.

    >
    > References were invented to provide more options when passing parameters
    > to functions and returning values from functions. I suggest you don't
    > use references in other contexts.
    >


    Ok, thanks.

    > > And also I would guess when I want to create an indeterminate number
    > > of objects at runtime dynamically, which would presumably force me to
    > > use pointers as this is what new returns in C++ when creating objects
    > > of classes.

    >
    > I suggest you use one of the standard containers when you have to do the
    > above, usually vector.
    >


    Ok, I will use that (or one of the lib methods provided).

    Much appreciated, thankyou.

    Gordy.
    , Jan 16, 2009
    #3
    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. Dave Rudolf
    Replies:
    12
    Views:
    8,246
    Martijn Lievaart
    Feb 6, 2004
  2. Jeremy Smith
    Replies:
    2
    Views:
    572
    Jeremy Smith
    Aug 3, 2006
  3. Jess
    Replies:
    5
    Views:
    582
    Ron Natalie
    Jun 7, 2007
  4. Peng Yu
    Replies:
    5
    Views:
    381
    Juha Nieminen
    Sep 19, 2008
  5. srp113
    Replies:
    3
    Views:
    456
Loading...

Share This Page