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
.
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.
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.
Answers to questions are automatically generated and may not have been reviewed.
A quick guide to creating objects using lists, including std::initializer_list
, aggregate and designated initialization