Elliot Hatch
Elliot Hatch

Reputation: 1110

Using a different base constructor for a derived class C++

From my understanding the following code will execute in this order:

  1. Derived constructor is called.
  2. Base object is constructed using the default base constructor.
  3. Body of the derived constructor executes.

If so, isn't the member z is assigned a value twice?

class base {
public:
    int x, y, z;
    base() {x = 0; y = 0; z = 0;};
};

class derived : public base {
public:
    derived() {z = 5;};
};

Is there a more efficient way to create an object of class "derived" so it uses a different constructor, in this case, one that would only assign members x and y a value, leaving z to be assigned a value in derived()?

Upvotes: 0

Views: 248

Answers (5)

In silico
In silico

Reputation: 52159

Sure. Use what's called a ctor-initializer:

class base {
public:
    int x, y, z;
    base(int z = 0) : x(0), y(0), z(z) {};
};

class derived : public base {
public:
    derived() : base(5) {}
};

The code after the : and before the first { in the constructor declaration is a ctor-initializer. (Some people call it an "initializer list", but ctor-initializer is what the C++ standard calls it.)

You should always use ctor-initializers whenever you can to initialize class members to some value. While it doesn't really matter for ints, initialization using ctor-initializers can be faster than default constructing class members then assignment.

Upvotes: 1

Crashworks
Crashworks

Reputation: 41384

To elaborate on Andrew's answer, if you wanted to really make sure that all of base's members were set only once, and in the most efficient way possible, you could use a member-list initializer rather than setting values in the constructor.

class base {
public:
    int x, y, z;
    base() : x(0), y(0), z(0) {};
    base( int xval, int yval, int zval ) : 
            x(xval), y(yval), z(zval) 
            { };
};

class derived : public base {
public:
    derived() : base( 0, 0, 5 ) {};
};

Most compilers will generate the same code for : x(_x), ... as just setting the values in the constructor, but I've seen a couple that did not.

Upvotes: 0

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361412

Definitely, you can do that.

Use member-initialization-list as:

class base {
public:
    int x, y, z;
    base(int a, int b, int c) : x(a), y(b), z(c) {}
                           //^^^^^^^^^^^^^^^^^^^ it's member-initialization-list!

};

class derived : public base {
public:
    derived() : base(0,0,5) {}
            // ^^^^^^^^^^^ call the specific base constructor
};

Upvotes: 0

Seth Carnegie
Seth Carnegie

Reputation: 75130

Yes, z is assigned twice in your example, just what it looks like.

To do what you're wanting, you could do something like this, which requires almost exactly the same amount of code (just moving some here and there):

class base {
public:
    int x, y, z;
    base(int z = 0) : x(), y(), z(z) { }
};

class derived : public base {
public:
    derived() : base(5) { } // with this one, z is assigned 5 once
    // or
    derived() { } // z is assigned 0 once
};

Upvotes: 1

Andrew Shepherd
Andrew Shepherd

Reputation: 45252

Yes, there is a more efficient way, but it will take more code (thus increasing the maintenance overhead).

class base {
public:
    int x, y, z;
    // Default constructor
    base() {x = 0; y = 0; z = 0;};
    // Constructor to be called if you want to override the z value
    base(int zValue) { x=0; y=0; z=zValue; };
};

class derived : public base {
public:
    derived() : base(5) {};
};

Upvotes: 3

Related Questions