Попытка вручную создать экземпляры класса unique_ptr с виртуальными частями

В качестве магистерской диссертации мне нужно расширить функциональность базы данных duckdb на github.

Одним из первых шагов было создание фиксированного внутреннего плана, который представлял бы что-то вроде "выберите 42;" просто на физическом уровне. С этой целью я устал вручную создавать такой план с классами, используемыми внутри duckdb.

При компиляции я обычно получаю такое сообщение об ошибке:

/home/ubuntu/git/duckdb/src/include/common/helper.hpp: In instantiation of ‘std::unique_ptr<T> duckdb::make_unique(Args&& ...)

 [with T = duckdb::Expression; Args = {duckdb::ExpressionType,
 duckdb::ExpressionClass, duckdb::TypeId}]’:   

 /home/ubuntu/git/duckdb/src/execution/physical_plan_generator.cpp:125:155:
 required from here   

 /home/ubuntu/git/duckdb/src/include/common/helper.hpp:24:23: error:

 invalid new-expression of abstract class type ‘duckdb::Expression’   
 return unique_ptr<T>(new T(std::forward<Args>(args)...));

Создание было этой строкой:

unique_ptr<Expression> ProjectionExpression = make_unique<Expression>(ExpressionType::VALUE_CONSTANT, ExpressionClass::BOUND_CONSTANT, TypeId::INTEGER);

Конструктор

Expression::Expression(ExpressionType type, ExpressionClass expression_class, TypeId return_type)
    : BaseExpression(type, expression_class), return_type(return_type) {
}

с базовым выражением

   BaseExpression(ExpressionType type, ExpressionClass expression_class)
        : type(type), expression_class(expression_class) {
    }
    virtual ~BaseExpression() {
    }

Как видите, выражение класса использует список инициализации из класса baseExpression. Насколько я могу судить, прямого наследования между ними нет, но, очевидно, мне нужно что-то, чего сейчас не хватает, чтобы правильно инициализировать конструктор.

Проблема в том, что обычно в duckdb эти вещи исходят от парсера и затем создаются из этих объектов. И я должен попытаться угадать, как должна выглядеть структура данных.

У меня возникли проблемы с выяснением того, как напрямую выделить этот объект с помощью make_unique, потому что выражение явно требует baseExpression somekind, но само базовое выражение имеет виртуальный компонент, поэтому я не могу просто создать его напрямую.

в основном я спрашиваю: как создать новый объект unique_ptr, когда класс абстрактный?

2 ответа

Как создать новый объект unique_ptr, когда класс абстрактный?

Создавая экземпляр конкретного неабстрактного подкласса и возвращая его в качестве указателя на абстрактный базовый класс. Это обычная практика при использовании шаблона Factory и подобных идиом.

Заглянув сюда в исходный код, вы увидите, чтоExpressionимеет чистую виртуальную функцию-член (узнаваем поvirtual и = 0):

class Expression : public BaseExpression {
    //...

    virtual unique_ptr<Expression> Copy() = 0;

    //...
 };

Класс с чистой виртуальной функцией-членом является абстрактным классом. Экземпляры абстрактных классов не могут быть созданы (будь то переменные с автоматической продолжительностью хранения, сnew или с std::make_unique). Вместо этого вам нужно выбрать соответствующий класс, производный отExpression который реализует все чистые виртуальные методы и создает экземпляр этого класса, например, вызывая std::make_unique<DerivedClass>(...). Вы все еще можете назначить этоstd::unique_ptr<Expression> потом.

Проблема не в виртуальных функциях-членах вообще, а только в чистых виртуальных функциях-членах. Без чистых виртуальных функций-членов классы с виртуальными функциями можно использовать сstd::make_unique без проблем.

Другие вопросы по тегам