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=2In 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=2In 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=3In 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