Похоже, что в ваших потомках Partition вы неправильно перенаправляете вызов в конструктор Partition.Вместо этого вы создаете временный объект Partition, а затем сразу же выбрасываете его.
struct Base {
Base() { cout << "Base Default" << endl; }
Base(int i) { cout << "Base Int: " << i << endl;
~Base() { cout << "~Base" << endl;
}
struct DerivedWrong : Base {
DerivedWrong(int i) {
Base(i);
cout << "Derived Int: " << i << endl;
}
};
Если вы создаете объект DerivedWrong
, на выходе должно быть
Base Default
Base Int: 5
~Base
Derived Int: 5
хитрый вызов деструктора перед выводом в конструктор производного класса?Это временный объект уничтожается.В конструкторе этого временного объекта он пытается вызвать RunAlgorithm
, который вы не реализуете, из-за ошибки компоновщика.Если бы вы сделали RunAlgorithm
чисто виртуальным [что вы должны сделать, между прочим], вы бы получили ошибку о создании абстрактного типа вместо ошибки компоновщика, которая могла бы быть более полезной для вас.Следующее теоретически решило бы проблему:
struct DerivedRight : Base {
DerivedRight(int i)
: Base(i)
{ cout << "Derived Int: " << i << endl; }
};
В этом случае результат - это то, что вы ожидаете.
Base Int: 5
Derived Int: 5
Однако, есть проблема: вы не можете вызватьвиртуальные функции из конструкторов базового класса и получают полиморфное поведение ... в итоге вы вызываете версию функции базового класса, независимо от того, была она переопределена или нет.Вы должны подождать, пока объект не будет полностью построен, прежде чем вы сможете получить полиморфное поведение.
По сути, на каждом этапе построения объект равен независимо от того, что строится.Даже если в конечном итоге это будет Triangulate
объект, в конструкторе Partition
он будет вести себя как Partition
.Это означает, что у вас все равно останется ошибка компоновщика.
Обратите внимание, что вы все равно можете вызывать виртуальные методы из конструкторов, вы просто должны быть в курсе этого поведения.Если вы абсолютно уверены, что Triangulate
и др. Никогда не будут производными, вы можете извлечь код из конструктора базового класса и поместить его в метод Init
, который вызывается из конструктора производного класса.В рамках этого метода виртуальная диспетчеризация будет работать так, как нужно.
Вы также можете рассмотреть ленивую инициализацию ... сохранить входные параметры и выполнять вычисления только при первом выполнении функтора.После этого просто верните кэшированные результаты.Это требует значительных дополнительных затрат, но дает преимущество в полной безопасности, независимо от того, как будет выглядеть ваша окончательная схема наследования.Функторы с состоянием имеют свои проблемы, в зависимости от того, как вы планируете использовать этот класс.