Попытка вручную создать экземпляры класса unique_ptr с виртуальными частями - PullRequest
0 голосов
/ 28 октября 2019

В качестве магистерской диссертации мне нужно расширить базу данных 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. Насколько я могу судить, между 2 нет прямого наследования, но ясно, что мне нужно что-то, чего в данный момент не хватает, чтобы правильно инициализировать конструктор.

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

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

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

Ответы [ 2 ]

0 голосов
/ 28 октября 2019

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

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

0 голосов
/ 28 октября 2019

Глядя на исходный код на здесь , вы видите, что 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 без проблем.

...