michalt38
michalt38

Reputation: 1193

Base class members initalization

Why the following code does not allow me to initalize base class member:

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : x(0) {} // error
};

while the following does:

class A { 
public:
   int x;
};

class B : public A {
public:
    B() { x = 0; } // ok
};

Upvotes: 1

Views: 78

Answers (2)

Vlad from Moscow
Vlad from Moscow

Reputation: 310920

This code snippet

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : x(0) {} // error
};

is incorrect because according to the C++ Standard (12.6.2 Initializing bases and members)

2 In a mem-initializer-id an initial unqualified identifier is looked up in the scope of the constructor’s class and, if not found in that scope, it is looked up in the scope containing the constructor’s definition. [ Note: If the constructor’s class contains a member with the same name as a direct or virtual base class of the class, a mem-initializer-id naming the member or base class and composed of a single identifier refers to the class member. A mem-initializer-id for the hidden base class may be specified using a qualified name. — end note ] Unless the mem-initializer-id names the constructor’s class, a non-static data member of the constructor’s class, or a direct or virtual base of that class, the mem-initializer is ill-formed.

Instead you could write

class A { 
public:
   int x;
};

class B : public A {
public:
    B() : A{ 0 } {}
};

where in the mem-initializer-list there is used the direct base class identifier.

Pay attention to that there are used braces A{ 0 } instead of parentheses because the class A is an aggregate.

In this code snippet

class A { 
public:
   int x;
};

class B : public A {
public:
    B() { x = 0; } // ok
};

The data member x is not present in the mem-initializer-list and is assigned in the body of the constructor after it was default initialized. That is in the body of the constructor there is used the assignment operator for already created object.

Upvotes: 1

alex berne
alex berne

Reputation: 699

Because the base-class is treated as a member in the initializer list.

You can picture your object of type B like this:

class C {
public:
    A parent;
};

In this example you wouldn't be able to initialize parent.x, but only parent. Even if you could access and modify parent.x in the body, just like you did, you cannot access its members in the initializer list:

C::C() {
    parent.x = 5; // Works
}

C::C() : parent.x(5) {} // Won't work

And on the other side, if you had a constructor for A like

A::A(int i): x(i) {}

, you could use this constructor in you initializer list for C:

C::C(): parent(5) {} // Works and does what you want

You have the same option for B, providing you have an constructor for A:

B::B(): A(5) {}

Upvotes: 2

Related Questions