У меня есть следующий простой код:
#include <iostream>
#include <vector>
template <class Derived>
struct Base
{
Base()
{
static_cast<Derived*>(this)->foo();
}
std::vector<int> m_ints;
};
struct Derived : Base<Derived>
{
Derived() : Base()
{
std::cout << a;
}
void foo()
{
m_ints.push_back(37);
a = 4;
}
int a;
};
int main()
{
Derived d;
return 0;
}
Я знаю о порядке вызова конструкторов при создании объекта. Конструктор вызывается из «самого базового -> вниз». Поэтому в конструкторе Base производный объект не полностью построен.
1) Безопасно ли звонить Derived::foo
в Base
конструктор, когда Derived::foo
не трогай Derived
объект? Я имею в виду, когда нет такой строки, как a = 4
, просто касаясь Base
объект.
2) Если я запускаю опубликованный код, он действительно работает, хотя я касаюсь a
который не должен существовать в то время. Это гарантия на работу? (Я проверил это на VS2013, VS2010 и GCC 4.8.1 на Ideone)
Это будет работать в этом конкретном случае, но я бы посоветовал не делать этого.
Незаметные изменения в коде могут внезапно нарушить логику (например, кто-то делает метод foo виртуальным, кто-то инициализирует элемент данных a в конструкторе или Derived, …).
Если базовый класс нуждается в информации из производного класса, то производный класс должен передать эту информацию конструктору базового класса. В этом классе значение 37 должно быть передано из конструктора Derived в конструктор Base.
И когда элемент данных a должен быть инициализирован, инициализируйте его в конструкторе Derived, а не где-нибудь еще.
РЕДАКТИРОВАТЬ: В C ++ 11, если класс Derived хочет внедрить код в конструктор Base, он может передавать лямбду в Base. Затем Base просто выполняет лямбду в своем конструкторе.
Других решений пока нет …