Why Initializer Lists don’t Work with Base Members


As you might know, you cannot initialize a base member in a derived constructors initializer list:

struct Base {
    int base_mem;
};

struct Derived : public Base {
    Derived(int i) : base_mem(i) {} //Error!
};

int main() {
    Derived(42);
}

This is not allowed. But why? There are two key points to get here:

1: What is the point of an initializer list in the first place?
If you don’t use an initializer list, but initialize all your objects in the constructor body, they will first be created once, even before the constructor body, and then you will re-assign them. This might be a performance-problem, but could also be a bigger problem if the constructors of those types have side-effects like hitting a database, acquiring some resource etc.

2: When are the different parts of an object constructed?
When constructing a Derived object, the first thing that happens is that Bases default constructor is invoked. In this example, I didn’t declare one, so the compiler will generate one for me. When this constructor is done, including both its initializer-list and its body, it is Derived()s turn.

This means that when C++ gets around to Derived()s initializer, the Base part of the object has already been created, all Base members are initialized, and we have lost the advantage of using initializer lists.

So how do we solve this? Make sure the Derived constructor explicitly specifies which Base constructor to use, and have this one initialize the variable. Example:

struct Base {
    Base(int i) : base_mem(i) {}
    int base_mem;
};

struct Derived : public Base {
    Derived(int i) : Base(i) {}
};

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s