C ++ - Невозможно передать производный тип как список базовых типов в конструктор - PullRequest
0 голосов
/ 05 марта 2019

Я пытаюсь реализовать класс, который состоит из переменного числа различных реализаций одного и того же абстрактного базового класса.Вот минимальный пример:

struct Base {
    virtual ~Base() {}
    virtual void something() const = 0;
}

Существует два класса (Derived1 и Derived2), которые извлекаются из этой базы:

class Derived1 : public Base {
public:
    void something() const override {
        std::cout << "derived 1" << std::endl;
    }
};

class Derived2 : public Base {
public:
    void something() const override {
        std::cout << "derived 2" << std::endl;
    }
};

Что я хочу сделать, это передать экземпляры этихклассы в другой класс (коллекция) с помощью конструктора.Я пытался добиться этого, используя std :: initializer_list:

class Collection {
public:
    Collection(std::initializer_list<Base> args) {
        for(auto& arg: args) {
            arg.something();
        }
    }
};

Когда я тогда пытаюсь вызвать этот конструктор как этот

Derived1 d1;
Derived2 d2;
Collection col({d1, d2});

, он не компилируется.Вот сообщения об ошибках, которые я получаю:

не может выделить объект абстрактного типа 'Base'
, потому что следующие виртуальные функции являются чистыми в пределах 'Base':
'virtual voidBase :: кое-что () const '

Похоже, ему нужно создать экземпляр абстрактного базового класса, но почему?Я ожидаю, что это как-то связано с конструктором копирования, вызываемым в классе списка инициализаторов, но я не получаю сообщение об ошибке, указывающее, что это так.Я чувствую, что упускаю что-то невероятно простое здесь, я просто не могу найти это ...

Ответы [ 2 ]

0 голосов
/ 05 марта 2019

Похоже, что ему нужно создать экземпляр абстрактного базового класса

Нет, вы не можете создать экземпляр абстрактного базового класса.Вместо этого вы создаете экземпляры производных классов и затем используете ссылки на базовый класс или указатели на этот экземпляр.

То, что вы пытаетесь сделать, сравнимо с

Derived1 d1; // Ok, create subclass instance
Base b = d1; // Not ok, copies only the Base part of d1, discards the rest

Это называется нарезкой объектов.Вместо этого вы можете перейти с

Base& b1 = d1; // Ok, reference to d1 doesn't copy/slice anything
Base *b2 = &d1; // Pointers are ok, too

Применительно к вашему сценарию вы можете определить конструктор для Collection как

Collection(std::initializer_list<const Base*> args) {
    for(auto *arg: args) {
        arg->something();
    }
}

и создать его экземпляр с помощью

Collection col({&d1, &d2});
0 голосов
/ 05 марта 2019

std::initializer_list<Base> - это набор объектов, чей тип самого производного равен Base.Такой коллекции не может быть, потому что Base является абстрактным.

Возможно, вам нужна коллекция указателей или ссылок на Base, например std::initializer_list<std::reference_wrapper<Base>>

...