From my understanding the following code will execute in this order:
- Derived constructor is called.
- Base object is constructed using the default base constructor.
- 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()?
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) {};
};
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
};
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.
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.
精彩评论