可以说我有一个抽象类,它的创建和复制非常昂贵:
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";
}
};
此外,我想创建一个使用
FirstDerived
或SecondDerived
通过组合(而不是聚合)的类。这意味着我希望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
没有虚拟析构函数。你应该解决这个问题。