C++与抽象类的组合

don*_*ger 2 c++ oop optimization composition c++11

假设我有一个抽象类,创建和复制是昂贵的:

class AbstractBase {
public:
    AbstractBase() {
        for (int i = 0; i < 50000000; ++i) {
            values.push_back(i);
        }
    }

    virtual void doThing() = 0;

private:
    vector<int> values;
};
Run Code Online (Sandbox Code Playgroud)

它有两个子类FirstDerived:

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

};
Run Code Online (Sandbox Code Playgroud)

并且SecondDerived:

class SecondDerived : public AbstractBase {
public:
    void doThing() {
        std::cout << "I did the thing in SecondDerived!\n";
    }
};
Run Code Online (Sandbox Code Playgroud)

此外,我想创建一个使用FirstDerivedSecondDerived使用组合(不是聚合)的类.意思是说我想ComposedOfAbstractBase自己取临时的传递如果我没有使用这一类抽象类会是什么样子.(在C++ 11)

class ComposedOfWhicheverDerived {
public:
    ComposedOfWhicheverDerived(AbstractBase abstract_base) : abstract_base(std::move(abstract_base)) {;}
private:
    AbstractBase abstract_base;
};
Run Code Online (Sandbox Code Playgroud)

但是,这不适用于抽象类,因为我不能创建一个实例AbstractBase,即使我小心不传入临时类AbstractBase,如下所示:

ComposedOfWhicheverDerived a(FirstDerived());
Run Code Online (Sandbox Code Playgroud)

对于编译器来说,这与以下一样糟糕:

ComposedOfWhicheverDerived b(AbstractBase());
Run Code Online (Sandbox Code Playgroud)

因为我AbstractBase在类声明中仍然有一个实例.

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

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

private:
    AbstractBase& some_derived_instance;
};
Run Code Online (Sandbox Code Playgroud)

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

ComposedOfAbstractBase a(FirstDerived());
ComposedOfAbstractBase b(SecondDerived());
Run Code Online (Sandbox Code Playgroud)

它不会创建任何AbstractBase临时传入的副本,并且AbstractBase允许存储对a的引用.虽然充其量只是对rvalue引用的引用似乎不清楚:它没有传达它ComposedOfAbstractBase 拥有的任何临时传递.除此之外,事实证明这个解决方案似乎是次优的.为了表明这一点,我创建了这个类:

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

private:
    FirstDerived first_derived;
};
Run Code Online (Sandbox Code Playgroud)

其中只能采取一个FirstDerived,所以我们可以申请std::move临时的卸载所有权.我可以像这样制作一个实例:

ComposedOfFirstDerived c(FirstDerived()); 
Run Code Online (Sandbox Code Playgroud)

有趣的是,这个类的创建速度始终要快10%ComposedOfAbstractClass.

有谁知道这里发生了什么?为什么ComposedOfFirstDerived创建的速度要快得多ComposedOfAbstractBase?是否有更好的方法来使用抽象类进行组合,还是我坚持使用次优解?

对不起,如果这是一个问题.我感谢任何花时间阅读并给出真实答案的人,因为我无法忍受!

Bar*_*rry 7

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;
};
Run Code Online (Sandbox Code Playgroud)

请注意,您AbstractBase没有虚拟析构函数.你应该解决这个问题.