Aggregate Initialization with Inheritance
How does aggregate initialization interact with inheritance and derived classes?
Aggregate initialization in C++ has specific rules when it comes to inheritance. Generally, aggregate initialization cannot be used directly with derived classes if they have base classes that are not aggregates themselves. Let's delve into this with an example.
First, consider a base class and a derived class:
#include <iostream>
struct Base {
int a;
};
struct Derived : public Base {
int b;
};
int main() {
Derived d{1, 2};
std::cout << "a=" << d.a
<< ", b=" << d.b;
}
a=1, b=2
In this example, Base
is an aggregate because it has no user-defined constructors or private members. Consequently, Derived
can also use aggregate initialization, inheriting the properties of Base
.
Non-Aggregate Base Types
If Base
has private members or user-defined constructors, Derived
cannot use aggregate initialization directly:
#include <iostream>
struct Base {
int a;
Base() {};
};
struct Derived : public Base {
int b;
};
int main() {
Derived d{1, 2};
}
error: 'initializing': cannot convert from 'int' to 'Base'
This code will not compile because Base
now has a user-defined constructor, making it non-aggregate. Therefore, Derived
also becomes non-aggregate, and aggregate initialization cannot be used.
To properly initialize such classes, you must use constructors:
#include <iostream>
struct Base {
int a;
Base(){};
Base(int x) : a{x} {}
};
struct Derived : public Base {
Derived(int x, int y) : Base{x}, b{y} {}
int b;
};
int main() {
Derived d{1, 2};
std::cout << "a=" << d.a
<< ", b=" << d.b;
}
a=1, b=2
In this code, Derived
has a constructor that initializes the base class Base
and its own member b
. This is the correct approach when dealing with inheritance and aggregate initialization limitations.
Multiple Inheritance
Another point to consider is multiple inheritance:
#include <iostream>
struct Base1 {
int a;
};
struct Base2 {
int b;
};
struct Derived : public Base1, public Base2 {
int c;
};
int main() {
Derived d{{1}, {2}, 3};
std::cout << "a=" << d.a
<< ", b=" << d.b
<< ", c=" << d.c;
}
a=1, b=2, c=3
In multiple inheritance, you can still use aggregate initialization if all base classes and the derived class are aggregates. Each base class is initialized in the order of inheritance.
In summary, aggregate initialization works with inheritance as long as all involved classes are aggregates. When base classes have private members or user-defined constructors, you must use constructors for initialization in derived classes.
List, Aggregate, and Designated Initialization
A quick guide to creating objects using lists, including std::initializer_list
, aggregate and designated initialization