简体   繁体   中英

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 ya value, leaving z to be assigned a value in derived()?

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) {};
};

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-initializer s whenever you can to initialize class members to some value. While it doesn't really matter for int s, initialization using ctor-initializer s can be faster than default constructing class members then assignment.

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
};

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
};

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM