| This page last updated on: May 16, 2001 Contents and Related Links
CodeWrangler Pages |
OverviewI consider object initialization in C++ to be one of the most important concepts to understand and to become proficient in. Everyone who designs and implements C++ classes and class libraries should be expert in the fundamental rules and details of how objects are created and initialized, according to the language standards.One reason that understanding object creation and initialization is so important is that there are critical performance implications. I'm fond of using the term "under the hood", and the C++ language will make sure that some kind of initialization is performed, typically "under the hood", even if it's unnecessary or not the wanted form of initialization. To help in understanding object initialization, this Web page gives a short overview of constructors (default and regular), member data initialization, and base object initialization. ConstructorsThis page assumes basic knowledge of constructors. Keep in mind the restrictions on constructors - they cannot be virtual, static, const or volatile functions, and are not inherited. Also, an object of a class with a constructor cannot be a member of a union, cannot specify a return type (not even void, although a return statement without a return value may be used), and the address of a constructor function cannot be taken.An important note - the constructor is the only way to initialize and modify const objects. This includes both const objects created at the application level, and const objects that are included in a class as member data. Example: const Xyz xyzObj(arg1, arg2); // ctor with arg1, arg2 is only way xyzObj
// can be initialized and modified
cout << xyzObj.fct1(some_arg); // must be a const member fct
class Foo {
public:
Foo (int x, int y) : mXyz (x, y) // only way to init or modify mXyz
{ /* Foo ctor code */ }
private:
const Xyz mXyz;
};
Foo fooObj (arg1, arg2); // member data mXyz is init'ed appropriately
Foo anotherFooObj; // Error - no default ctor (see next section)
Remember that the member initialization list, used to initialize base and
member data objects, is in the definition, not declaration of the constructor.
The preceding example had both the declaration and definition written together
in the header file for brevity.
Default ConstructorsA default constructor is a constructor taking no arguments (or a constructor with all the arguments having defaults). Default constructors and copy constructors are generated by the compiler, when appropriate. Generated default constructors are public.Important note: If one or more constructors are created by the programmer, then the compiler will not create a default constructor. Usage that requires a default constructor will generate a compiler error if the programmer has not explicitly declared (and later defined) a default destructor. Example: class Xyz { /* ... no default ctor */ };
class Foo {
public:
Foo (int i, int j) { /* ctor code */ } // NOTE - no default ctor
// ...
};
class Mnm {
public:
Mnm () { /* default ctor code */ }
//... // other ctors and member fcts as needed
};
Xyz xyzObj; // default ctor generated
Foo fooObj; // ERROR - user needs to provide default ctor
Mnm chocFlavor; // user specified default ctor is invoked
This is specially important to remember when new'ing an array
of objects - unless a default constructor is defined for the class, the
objects cannot be created and initialized. It is also necessary for any
member data objects that are not explicitly initialized through one of
the enclosing class constructors member initialization list. If the member
data object is not explicitly initialized and it has one or more constructors
defined, one of them must be a default constructor. If there are no constructors
defined for the member data object, the compiler will generate one.
From the C++ draft standard (December 1996 Working Paper): If there is no user-declared constructor for class X, a default constructor is implicitly declared. An implicitly-declared default constructor is an inline public member of its class. Object InitializationWhile the default constructor must be used when new'ing arrays of objects, if the array is allocated statically or on the stack, there is a way to specify arguments for each object using the brace initializer syntax.Example: class Foo {
public:
Foo ();
Foo (int i);
Foo (int i, int j);
// ...
};
Foo a[6] = {10, Foo(3,4), Foo(), 22};
// a[0] inited with Foo(10), a[1] with Foo(3,4), a[2] with Foo(), a[3] with
// Foo(22), and the rest with the default Foo constructor
For completeness and compatibility with ISO/Ansi C, a class with no constructors,
no private or protected members, no base classes, and no virtual functions
(which is equivalent to a traditional C struct - the reference
manuals call this an aggregate) can be initialized with a brace-enclosed
initializer-list.
Example: struct X { int a; char* b; int c; };
X xObj = { 1, "hi there" };
Initialization OrderThe general order of initialization is:
There's a common sense reason why the constructor code is executed last - the constructor may operate upon member or base object data, which must be already initialized and ready to be modified or accessed. Destructors are called in the reverse order (which is the main reason why initialization is dependent on declaration order, rather than on the order in the initialization list). From Stroustrup, The C++ Programming Language, 2nd edition: Virtual base classes constitute a special case. Virtual bases are constructed before any nonvirtual bases and in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes; 'left-to-right' is the order of appearance of the base class names in the declaration of the derived class.From Stroustrup, The C++ Programming Language, 3rd edition:
Different Ways to Construct and DestructFrom Stroustrup, The C++ Programming Language, 3rd edition:
|