Consider the following code:
#include <iostream>
struct Parent {
int baseA_ = 0;
double baseB_ = 0.0;
Parent() = default;
virtual ~Parent() = default;
Parent(int a) : baseA_{a} {}
Parent(int a, double b) : baseA_{a}, baseB_{b} {}
auto set(int a) -> void { baseA_ = a; }
auto set(int a, double b) -> void {
baseA_ = a;
baseB_ = b;
}
};
struct AnotherParent {
std::string baseA_ = {};
AnotherParent() = default;
virtual ~AnotherParent() = default;
AnotherParent(const std::string &a) : baseA_{a} {}
auto set(const std::string &a) -> void { baseA_ = a; }
};
// Notice that the `Child` class inherits from T.
template <typename T>
struct Child : public T {
int derivedA_ = 0;
Child() = default;
~Child() = default;
Child(int a) : derivedA_{a} {}
auto super(auto... args) -> Child & {
T::set(args...);
return (*this);
}
};
int main() {
auto c1 = Child<Parent>(23).super(23, 3.5);
auto c2 = Child<AnotherParent>(243).super("Hello, World!");
std::cout << "C1 - Base -> A: " << c1.baseA_ << ", B: " << c1.baseB_
<< std::endl;
std::cout << "C1 - Derived -> A: " << c1.derivedA_ << std::endl;
std::cout << "C2 - Base -> A: " << c2.baseA_ << std::endl;
std::cout << "C2 - Derived -> A: " << c2.derivedA_ << std::endl;
return 0;
}
To compile use:
g++ -std=c++17 -fconcepts Main.cpp
or
g++ -std=c++14 -fconcepts Main.cpp
I want to initialize both child class (inherited from template class type) and parent class fields during instantiation. I don't want to pass a parent class object as parameter to constructor.
super class
(i mean it) data fields for any type.compiler-error
if set()
method is not suitable.super class
data fields
(Infact, no one can overload child class constructor to match any super class, or is it possible?, I am not sure).super()
is optional.set()
method.super
- Is is a good practice?-fconcepts
?set()
method.You could replace your super
method with a template constructor that forwards to the base class.
template <typename T>
struct Child : public T {
int derivedA_ = 0;
Child() = default;
~Child() = default;
Child(int a) : derivedA_{a} {}
template <typename... Args>
Child(int a, Args&&... args) : T{std::forward<Args>(args)...}, derivedA_{a} {}
};
Now you can use it like so
auto c1 = Child<Parent>(23, 23, 3.5);
auto c2 = Child<AnotherParent>(243, "Hello, World!");
auto c3 = Child<Parent>(23, 42);
Edit:
Just a note on AnotherParent
s constructor. Since you pass in the std::string
by const ref you will always have to copy it into the member.
In that scenario, it's better to take the parameter by value. You will still at worst make one copy there too, but when we pass in an rvalue to the constructor we get a move instead of a copy.
AnotherParent(std::string a) : baseA_{std::move(a)} {}