避免使用组合进行额外的堆分配(过度继承)

Avoiding extra heap allocations with composition (over inheritance)?

本文关键字:分配 继承 组合      更新时间:2023-10-16

tl;dr-Composition似乎是适合我的情况的正确设计选择,但我希望避免为我一起组合的每个对象分配堆的开销。有什么好的技巧吗?

我有一个设置,看起来像:

class Foo {
public:
Foo(unique_ptr<FooEvaluator> evaluator) 
: evaluator_(std::move(evaluator)),
common_state_() {}
void FooMethod() {
// Perform some common processing.
evaluator.DoSomething();
}
private:
unique_ptr<FooEvaluator> evaluator_;
Bar common_state_;
}
class FooEvaluator {
public:
virtual void DoSomething() = 0;
}
class FooEvaluatorImpl : public FooEvaluator {
public:
FooEvaluatorImpl(type1 arg) {…}
void DoSomething() override {…}
}
class FooEvaluatorImplVariant : public FooEvaluator {
public:
FooEvaluatorImplVariant(type2 arg) {…}
void DoSomething() override {…}
}

粗略地说:我有一个Foo,它做一些常见的处理,然后使用FooEvaluator。我有几个FooEvaluator实现,每个实现都有一些不同的逻辑。常见的Foo处理非常简单,因此尽量避免重复它是有意义的

我担心的是,现在我必须分配两个对象,而不是只有一个,如果我有一个包含共享逻辑和评估逻辑的整体Foo。

我能想到的一个模糊合理的中间立场是让FooEvaluator继承Foo,并在Foo上添加DoSomething()作为私有虚拟方法。这有点滥用继承imo(你不能说FooEvaluator是Foo),但它会得到我的共享代码,并避免双重内存分配。

有什么想法吗?

您可以使用模板进行类似操作:

template <typename Evaluator>
class Foo {
public:
template <typename ... Ts>
Foo(Ts&&... args) 
: evaluator_(std::forward<Ts>(args)...),
common_state_()
{}
void FooMethod() {
// Perform some common processing.
evaluator.DoSomething();
}
private:
Evaluator evaluator_;
Bar common_state_;
};

好吧,由于我不知道Foo的复杂性/细节,我建议将其作为内联函数,然后您可以从几个FooEvaluator实例中调用它,以便在执行细节之前完成常见的处理。