带有抽象类的c++组合

C++ Composition with abstract class

本文关键字:c++ 组合 抽象类      更新时间:2023-10-16

假设我有一个抽象类,它的创建和复制成本很高:

class AbstractBase {
public:
    AbstractBase() {
        for (int i = 0; i < 50000000; ++i) {
            values.push_back(i);
        }
    }
    virtual void doThing() = 0;
private:
    vector<int> values;
};

有两个子类FirstDerived:

class FirstDerived : public AbstractBase {
public:
    void doThing() {
        std::cout << "I did the thing in FirstDerived!n";
    }
};

SecondDerived:

class SecondDerived : public AbstractBase {
public:
    void doThing() {
        std::cout << "I did the thing in SecondDerived!n";
    }
};

进一步,我想创建一个使用组合(而不是聚合)利用FirstDerivedSecondDerived的类。这意味着我希望ComposedOfAbstractBase 拥有传入的。如果我没有在这个类中使用抽象类,这个类看起来像:(在c++ 11中)

class ComposedOfWhicheverDerived {
public:
    ComposedOfWhicheverDerived(AbstractBase abstract_base) : abstract_base(std::move(abstract_base)) {;}
private:
    AbstractBase abstract_base;
};

然而,这对抽象类不起作用,因为我不能创建AbstractBase的实例,即使我小心地不传递临时AbstractBase,像这样:

ComposedOfWhicheverDerived a(FirstDerived());

对于编译器来说,这和:

一样糟糕
ComposedOfWhicheverDerived b(AbstractBase());

因为在类声明中仍然有一个AbstractBase的实例。

我想到的下一个解决方案是:

class ComposedOfAbstractBase {
public:
    ComposedOfAbstractBase(AbstractBase&& abstract_base) : some_derived_instance(abstract_base) {;}
private:
    AbstractBase& some_derived_instance;
};

这工作完美(即使我不完全理解它)!这两个实例都是有效的,并按预期工作:

ComposedOfAbstractBase a(FirstDerived());
ComposedOfAbstractBase b(SecondDerived());

它不创建任何AbstractBase临时传入的副本,并且允许存储对AbstractBase的引用。虽然对右值引用的引用充其量看起来是不清楚的:它没有传达ComposedOfAbstractBase 拥有传入的临时值。除此之外,这个解决方案似乎不是最优的。为了说明这一点,我创建了这个类:

class ComposedOfFirstDerived {
public:
    ComposedOfFirstDerived(FirstDerived first_derived) : first_derived(std::move(first_derived)) {;}
private:
    FirstDerived first_derived;
};

只能占用FirstDerived,所以我们可以应用std::move来卸载临时寄存器的所有权。我可以这样创建一个实例:

ComposedOfFirstDerived c(FirstDerived()); 

有趣的是,创建这个类始终比创建ComposedOfAbstractClass快10%。

有人知道这里发生了什么吗?为什么ComposedOfFirstDerived的创建速度比ComposedOfAbstractBase快得多?是否有更好的方法来使用抽象类进行组合,或者我是否陷入了次优解决方案?

如果这是一个拗口的问题,我很抱歉。我感谢任何花时间通读它并给出真实答案的人,因为我被难住了!

ComposedOfAbstractBase不是解决方案。你拿着一个悬空的引用。

由于AbstractBase,顾名思义,是抽象的-您不能按值保存一个。只能通过引用或指针保存一个。因为引用不能拥有对象,所以只能使用指针。而拥有指针的现代方式是使用unique_ptr:

class ComposedOfAbstractBasePtr {
public:
    ComposedOfAbstractBasePtr(std::unique_ptr<AbstractBase> p)
    : some_derived_instance(std::move(p))
    { }
private:
    std::unique_ptr<AbstractBase> some_derived_instance;
};

注意你的AbstractBase没有虚析构函数。你应该解决这个问题。