Вы можете попробовать создать свои конструкторы Mixin с помощью шаблонов variadi c и совершенной пересылки, поэтому вам не нужно определять версию для каждого возможного числа аргументов.
struct B : public A {
template<typename... Args>
B(Args&&... args) : A(std::forward<Args>(args)...) { this->validate(); }
};
Задумывались ли вы о дать Mixin переменную-член типа класса «validator», конструктор которого берет указатель на Mixin и просто вызывает validate
для него? Таким образом, вам не нужно создавать конструктор для Mixin (просто определите инициализатор по умолчанию для вашего члена «validator»), и он будет запущен точно в то время, когда ваш конструктор Mixin будет.
struct B : public A {
using A::A;
struct V { V(B & b) { b.validate(); } };
V v_ = { *this };
};
С C ++ 20-х [[no_unique_address]]
https://en.cppreference.com/w/cpp/language/attributes/no_unique_address вам даже не придется платить штраф за использование пустого члена.
Порядок разрешения методов гарантирует что функции, вызываемые из конструктора, сначала вызываются из производного класса) В C ++ динамическое связывание отключено в конструкторах (я понимаю причины). Вызов виртуальной функции void init () не будет работать, поскольку всегда вызывается функция базового класса.
Не уверен, что вы подразумеваете под этим. См. Этот пример: https://godbolt.org/z/RVSkpi
#include <iostream>
struct A {
virtual int a() { std::cout << "A::a\n"; return 1; }
virtual int b() { std::cout << "A::b\n"; return a(); }
};
struct B : public A {
virtual int a() { std::cout << "B::a\n"; return 2; }
virtual int b() { std::cout << "B::b\n"; return a(); }
B() : a_(b()) { b(); }
int a_;
};
int main() {
B b;
return 0;
}
До того, как первый конструктор членов B
будет выполнен (и после того, как конструктор A
завершит выполнение), объект будет Конструкция «становится» типа B
и остается таким до конца конструктора B
(после чего он может стать другим типом, который наследуется от B
). В конструкторе виртуальный поиск просто не нужен, поскольку компилятор знает , что тип точно равен B
, и может разрешать вызовы методов статически. Но он не может сделать это для вызова a()
из b()
, поскольку он может быть вызван не только из конструктора. Но, поскольку в данный момент будет вызываться b()
, тип объекта Dynami c равен B
, они также будут преобразованы в вызовы B::a
во время выполнения.
РЕДАКТИРОВАТЬ: Если вы хотите, чтобы дополнительный производный класс предоставлял функцию проверки, как упомянуто в комментариях, и у вас нет C ++ 20, вы можете попробовать что-то вроде этого: https://godbolt.org/z/r23xJv
#include <iostream>
struct A {
A(int a) : a_(a) {}
int a_;
};
template<typename T, typename VF>
struct B : T {
using A::A;
struct V { V(B & b) { VF::verify(b); } };
V v_ = { *this };
};
struct C : B<A, C> {
using B::B;
static void verify(B & b) { std::cout << b.a_ << "\n"; }
};
int main(int argc, char* argv[]) {
C c(123);
return 0;
}