MFC Programmer's SourceBook : Thinking in C++
Bruce Eckel's Thinking in C++, 2nd Ed Contents | Prev | Next

The constructor initializer list

You’ve seen how important it is in C++ to guarantee proper initialization, and it’s no different during composition and inheritance. When an object is created, the compiler guarantees that constructors for all its subobjects are called. In the examples so far, all the subobjects have default constructors, and that’s what the compiler automatically calls. But what happens if your subobjects don’t have default constructors, or if you want to change a default argument in a constructor? This is a problem because the new class constructor doesn’t have permission to access the private data elements of the subobject, so it can’t initialize them directly.

The solution is simple: Call the constructor for the subobject. C++ provides a special syntax for this, the constructor initializer list. The form of the constructor initializer list echoes the act of inheritance. With inheritance, you put the base classes after a colon and before the opening brace of the class body. In the constructor initializer list, you put the calls to subobject constructors after the constructor argument list and a colon, but before the opening brace of the function body. For a class MyType, inherited from Bar, this might look like

MyType::MyType(int i) : Bar(i) { // ...

if Bar has a constructor that takes a single int argument.

Member object initialization

It turns out that you use this very same syntax for member object initialization when using composition. For composition, you give the names of the objects rather than the class names. If you have more than one constructor call in the initializer list, you separate the calls with commas:

MyType2::MyType2(int i) : Bar(i), memb(i+1) { // ...

This is the beginning of a constructor for class MyType2, which is inherited from Bar and contains a member object called memb. Note that while you can see the type of the base class in the constructor initializer list, you only see the member object identifier.

Built-in types in the initializer list

The constructor initializer list allows you to explicitly call the constructors for member objects. In fact, there’s no other way to call those constructors. The idea is that the constructors are all called before you get into the body of the new class’s constructor. That way, any calls you make to member functions of subobjects will always go to initialized objects. There’s no way to get to the opening brace of the constructor without some constructor being called for all the member objects and base-class objects, even if the compiler must make a hidden call to a default constructor. This is a further enforcement of the C++ guarantee that no object (or part of an object) can get out of the starting gate without its constructor being called.

This idea that all the member objects are initialized by the opening brace of the constructor is a convenient programming aid, as well. Once you hit the opening brace, you can assume all subobjects are properly initialized and focus on specific tasks you want to accomplish in the constructor. However, there’s a hitch: What about embedded objects of built-in types, which don’t have constructors?

To make the syntax consistent, you’re allowed to treat built-in types as if they have a single constructor, which takes a single argument: a variable of the same type as the variable you’re initializing. Thus, you can say

class X {
  int i;
  float f;
  char c;
  char* s;
public:
  X() : i(7), f(1.4), c(‘x’), s("howdy") {}
  // ... 
The action of these “pseudoconstructor calls” is to perform a simple assignment. It’s a convenient technique and a good coding style, so you’ll often see it used.

It’s even possible to use the pseudoconstructor syntax when creating a variable of this type outside of a class:

int i(100);

This makes built-in types act a little bit more like objects. Remember, though, that these are not real constructors. In particular, if you don’t explicitly make a pseudo-constructor call, no initialization is performed.

Contents | Prev | Next


Go to CodeGuru.com
Contact: webmaster@codeguru.com
© Copyright 1997-1999 CodeGuru