Reputation: 11
How to initialize class instance with initializer_list if class has base with virtual methods c++? I want to avoid writing constructors and use "lazy" way to initialize class like X x{"Some string"};
. But I got
error: no matching function for call to ‘X::X(<brace-enclosed initializer list>)’
Is any way to simply initialize X instance without significant changing of classes?
struct Y
{
virtual ~Y() = 0;
};
struct X : public Y
{
string msg;
virtual ~X() = default;
};
int main()
{
X x{"Some string"};
return 0;
}
Upvotes: 1
Views: 253
Reputation: 706
The comments already answer it. Here is a summary.
Short answer
No, there is no way - because that would be a aggregate initialisation (https://en.cppreference.com/w/cpp/language/aggregate_initialization) that is only possible when the class (struct) has:
Alternative 1
If there is just the attribute string msg
, then you can do the following.
#include <iostream>
using std::string;
using std::cout;
struct Y
{
virtual ~Y() = default; // !!! not pure virtual !!!
};
struct X : public Y
{
string msg;
virtual ~X() = default;
};
int main( int /*argc*/, char */*argv*/[] )
{
X x;
x.msg = "Some string";
cout << "int main( int /*argc*/, char */*argv*/[] ) - #1" << '\n';
return 0;
}
NOTE: In the code above, the destructor has been changed to virtual ~Y() = default;
otherwise the compiler complains about the missing destructor that is called from ~X()
. Linker error, may be:
Undefined symbols for architecture arm64:
"m1::Y::~Y()", referenced from:
m1::X::~X() in m1.o
NOTE: You may have no constructor that assures the consistency of states after construction.
Alternative 2
Make your attribute list a tuple.
#include <iostream>
using std::string;
using std::cout;
struct Y
{
virtual ~Y() = default;
};
typedef string TMessage;
typedef int TOtherAttribute;
using XAttributes = std::tuple<TMessage, TOtherAttribute>;
struct X : public Y
{
XAttributes mx;
X( XAttributes l ) : mx{ l } {
};
virtual ~X() = default;
template<typename T> void print() const {
cout << "member = " << get<T>( mx ) << '\n';
}
};
int main( int /*argc*/, char */*argv*/[] )
{
X x{ XAttributes{ "Some string", 34 } };
x.print<TMessage>();
x.print<TOtherAttribute>();
return 0;
}
Output:
member = Some string
member = 34
Upvotes: 0