Initialization of base classes and members (C++ only)
Constructors can initialize their members in two different ways.
A constructor can use the arguments passed to it to initialize member
variables in the constructor definition:
complx(double r, double i = 0.0) { re = r; im = i; }Or a constructor can have an initializer list within the
definition but prior to the constructor body:
complx(double r, double i = 0) : re(r), im(i) { /* ... */ }Both methods assign the argument values to the appropriate data members of the class.
Include the initialization list as part of the constructor definition,
not as part of the constructor declaration. For example:
#include <iostream>
using namespace std;
class B1 {
int b;
public:
B1() { cout << "B1::B1()" << endl; };
// inline constructor
B1(int i) : b(i) { cout << "B1::B1(int)" << endl; }
};
class B2 {
int b;
protected:
B2() { cout << "B2::B2()" << endl; }
// noninline constructor
B2(int i);
};
// B2 constructor definition including initialization list
B2::B2(int i) : b(i) { cout << "B2::B2(int)" << endl; }
class D : public B1, public B2 {
int d1, d2;
public:
D(int i, int j) : B1(i+1), B2(), d1(i) {
cout << "D1::D1(int, int)" << endl;
d2 = j;}
};
int main() {
D obj(1, 2);
}The following is the output of the above example:
B1::B1(int)
B1::B1()
D1::D1(int, int)If you do not explicitly initialize a base class or member that
has constructors by calling a constructor, the compiler automatically
initializes the base class or member with a default constructor. In
the above example, if you leave out the call
B2() in
the constructor of class D (as shown below), a constructor
initializer with an empty expression list is automatically created
to initialize B2. The constructors for class D,
shown above and below, result in the same construction of an object
of class D: class D : public B1, public B2 {
int d1, d2;
public:
// call B2() generated by compiler
D(int i, int j) : B1(i+1), d1(i) {
cout << "D1::D1(int, int)" << endl;
d2 = j;}
};In the above example, the compiler will automatically call the
default constructor for B2().
Note that you must declare constructors as public or protected
to enable a derived class to call them. For example:
class B {
B() { }
};
class D : public B {
// error: implicit call to private B() not allowed
D() { }
};The compiler does not allow the definition of D::D() because
this constructor cannot access the private constructor B::B().
You must initialize the following with an initializer list: base
classes with no default constructors, reference data members, non-static
const data members, or a class type which contains a constant data
member. The following example demonstrates this:
class A {
public:
A(int) { }
};
class B : public A {
static const int i;
const int j;
int &k;
public:
B(int& arg) : A(0), j(1), k(arg) { }
};
int main() {
int x = 0;
B obj(x);
};The data members j and k, as
well as the base class A must be initialized in the
initializer list of the constructor of B.
You can use data members when initializing members of a class.
The following example demonstrate this:
struct A {
int k;
A(int i) : k(i) { }
};
struct B: A {
int x;
int i;
int j;
int& r;
B(int i): r(x), A(i), j(this->i), i(i) { }
};The constructor B(int i) initializes the following:
B::rto refer toB::x- Class
Awith the value of the argument toB(int i) B::jwith the value ofB::iB::iwith the value of the argument toB(int i)
You can also call member functions (including virtual member functions)
or use the operators
typeid or dynamic_cast when
initializing members of a class. However if you perform any of these
operations in a member initialization list before all base classes
have been initialized, the behavior is undefined. The following example
demonstrates this: #include <iostream>
using namespace std;
struct A {
int i;
A(int arg) : i(arg) {
cout << "Value of i: " << i << endl;
}
};
struct B : A {
int j;
int f() { return i; }
B();
};
B::B() : A(f()), j(1234) {
cout << "Value of j: " << j << endl;
}
int main() {
B obj;
}The output of the above example would be similar to the
following: Value of i: 8
Value of j: 1234The behavior of the initializer A(f()) in
the constructor of B is undefined. The runtime will
call B::f() and try to access A::i even
though the base A has not been initialized.The following example is the same as the previous example except
that the initializers of
B::B() have different arguments: #include <iostream>
using namespace std;
struct A {
int i;
A(int arg) : i(arg) {
cout << "Value of i: " << i << endl;
}
};
struct B : A {
int j;
int f() { return i; }
B();
};
B::B() : A(5678), j(f()) {
cout << "Value of j: " << j << endl;
}
int main() {
B obj;
}The following is the output of the above example: Value of i: 5678
Value of j: 5678The behavior of the initializer j(f()) in
the constructor of B is well-defined. The base class A is
already initialized when B::j is initialized.
Beginning of C++0x only.
If the delegating constructors feature is enabled, initialization
can only be done within the non-delegating constructor. In other words,
a delegating constructor cannot both delegate and initialize. Consider
the following example:
struct A{
int x,y;
A(int x):x(x),y(0){}
/* the following statement is not allowed */
A():y(0),A(42) {}
};Constructor A() delegates to A(int
x), but A() also does the initialization,
which is not permitted. The compiler issues an error to indicate the
violation.For more information, see Delegating constructors (C++11)
End of C++0x only.
Related information
