首页 > c++ > C ++ - 无法将派生类型作为基类型列表传递给构造函数

C ++ - 无法将派生类型作为基类型列表传递给构造函数 (C++ - Cannot pass derived type as base type list to constructor)

问题

我正在尝试实现一个类,该类是从同一个抽象基类的不同实现构造的。这是一个最小的例子:

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;
    }
};

我想要做的是通过构造函数将这些类的实例传递给另一个类(Collection)。我试图使用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 void Base :: something()const'

看起来它需要构造一个抽象基类的实例,但为什么呢?我希望它与在初始化列表类中调用的复制构造函数有关,但我没有得到错误,表明情况就是这样。我觉得我在这里遗漏了一些非常基本的东西,我似乎无法找到它......

解决方法

看起来它需要构造一个抽象基类的实例

不,您无法创建抽象基类的实例。相反,您创建派生类的实例,然后使用基类引用或指向该实例的指针。

你要做的是与之相媲美的

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

应用于您的场景,您可以为Collectionas 定义构造函数

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

并通过实例化它

Collection col({&d1, &d2});

问题

I'm trying to implement a class which is constructed from a variable number of different implementations of the same abstract base class. Here's a minimal example:

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

There are two classes (Derived1 and Derived2) which are dervied from that base:

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;
    }
};

What I want to do is to pass instances of those classes to another class (Collection) via constructor. I have tried to achieve this using a std::initializer_list:

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

When I then try to call that constructor like this

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

it does not compile. Here's the error messages that I'm getting:

cannot allocate an object of abstract type 'Base'
because the following virtual functions are pure within 'Base':
'virtual void Base::something() const'

It looks like it needs to construct an instance of the abstract base class, but why? I would expect that it has something to do with a copy constructor being called within the initializer list class, but I get no error indicating this is the case. I feel like I'm missing something incredibly basic here, I just can't seem to find it...

解决方法

It looks like it needs to construct an instance of the abstract base class

No, you cannot create an instance of an abstract base class. Instead, you create instances of derived classes and then use base class references or pointers to that instance.

What you are trying to do is comparable to

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

This is called object slicing. You can instead go with

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

Applied to your scenario, you could define the constructor for Collection as

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

and instantiate it via

Collection col({&d1, &d2});
相似信息