Этот вопрос относится к этому другому. Я пытаюсь реализовать подход virtual method
, предложенный в одном из ответов.
У меня есть абстрактный базовый класс, представляющий объект, описываемый функцией Level-Set
class LevelSetObject
{
public:
virtual double SDF(double x, double y, double z) const = 0;
/** @brief Union of two LevelSetObjects */
CompositeLevelSetObject operator+(LevelSetObject& other);
virtual ~LevelSetObject() = default;
};
Первая реализация, которая у меня была с std::function
, работала более или менее как ожидалось. Разница в том, что я возвращаю CompositeLevelSetObject
при сложении двух обобщенных c LevelSetObjects
CompositeLevelSetObject LevelSetObject::operator+(LevelSetObject& other) {
CompositeFun* fun = [] (double sdf_value1, double sdf_value2) {
return std::min(sdf_value1, sdf_value2);
};
auto first = std::unique_ptr<LevelSetObject>(new LevelSetObject(*this));
auto second = std::unique_ptr<LevelSetObject>(new LevelSetObject(other));
return { std::move(first), std::move(second), fun };
}
A CompositeLevelSetObject
, по крайней мере, на мой взгляд :), это объект, который принимает как входные указатели на два объекта, из которых он состоит, плюс указатель на функцию, которая вычисляет результирующую функцию расстояния (примитивные комбинации LevelSetObjects
кодируются операциями между двумя отдельными функциями расстояния объектов ref ("Примитивные комбинации") )
/** @brief This is the function that is called on the two single SDF function of the objects */
using CompositeFun = double (double, double);
/**
* @brief A class representing a composite LevelSetObject coming out of operation between two other LevelSetObjects
*
* This class stores pointers to the two LevelSetObject and executes a given function on both of them
*/
class CompositeLevelSetObject : public LevelSetObject
{
using LevelSetObjectPtr = std::unique_ptr<LevelSetObject>;
private:
LevelSetObjectPtr m_first;
LevelSetObjectPtr m_second;
CompositeFun* m_fun;
public:
CompositeLevelSetObject() = default;
CompositeLevelSetObject(LevelSetObjectPtr first, LevelSetObjectPtr second, CompositeFun* m_fun);
CompositeLevelSetObject(CompositeLevelSetObject&&);
double SDF(double x, double y, double z) const override;
// :: Operators ::
CompositeLevelSetObject& operator=(CompositeLevelSetObject&&);
};
}
double CompositeLevelSetObject::SDF(double x, double y, double z) const {
return m_fun(m_first->SDF(x, y, z), m_second->SDF(x, y, z));
}
Это явно не работает, потому что в LevelSetObject::operator+
я создаю указатели, создающие экземпляр абстрактного класса.
allocating an object of abstract class type 'hgve::LevelSetObject'
auto first = std::unique_ptr<LevelSetObject>(new LevelSetObject(*this));
Поэтому я попытался переключить метод LevelSetObject::SDF
на не чистый, возвращая 0
. Но явно не работает, потому что тогда все возвращает 0.
Я упускаю что-то в моей концептуальной организации структуры данных, вероятно, из-за моего динамического c языкового фона, но я не вижу этого , Любая помощь приветствуется.
Пример использования:
// Vector containing a list of LevelSetSpheres
static std::vector<LevelSetSphere> elements = {
LevelSetSphere{radius, {radius, 0.25, 0.25}},
LevelSetSphere{radius, {radius + interDistance, 0.25, 0.25}},
LevelSetSphere{radius, {radius + 2*interDistance, 0.25, 0.25}}
};
int main(int argc, char* argv[]) {
// Sum first two elements
CompositeLevelSetObject soot = elements[0] + elements[1];
for(auto el = std::next(elements.begin(), 2); el != elements.end(); ++el) {
// Combine elements
soot = soot + *el;
}
}
LevelSetSphere
является производным классом от LevelSetObject
.
class LevelSetSphere : public LevelSetObject
{
private:
double m_R; /**< The radius of the sphere */
SimpleVector m_C; /**< The center of the sphere */
public:
/** @brief Constructor
*
* @param radius The radius of the sphere
*/
LevelSetSphere(double radius, SimpleVector center);
double SDF(double x, double y, double z) const override;
};