我有很多类型的 PixelMeasure
, PointMeasure
, CentimeterMeasure
等,代表带有单元的值。我希望他们有
- 价值语义:例如有效不变,不必担心内存分配,
- 多态性:我可以返回类型
Measure
的对象,并且可以在它上进行操作,而无需知道它是什么特定种类。我也希望能够将多个不同的Measure
S放入容器中。
看来这些在C 中是相互排斥的。对于多态性,我需要使用指针或参考。
我看到了两个选项:
- 使用智能指针,例如
shared_ptr
。这给了我想要的行为(安全,没有原始的指针,但多态调度)。缺点是:- 它是冗长的(如果我真的想要的话,我可以将其隐藏在Typedef后面)。
- 您的内存分配在引擎盖下方(但代码不是至关重要的,它被隐藏了)。
- 语义是Wierd的 - 我的对象(
shared_ptr<PixelMeasure>
)的副本将共享相同的基础指针。我仍然可以假装它具有价值语义 - 如果我使接口不变,那就没关系了。
- 我简短考虑了不使用继承(没有共同基类)并通过模板进行调度 - 但是在这种情况下,我需要在编译时知道确切的措施类型,并且不能将它们放入容器中。
- 我可以完全摆脱课程,只使用一个具有价值和单元字段的类,但这会较小的灵活性,并且使用语法会更糟,所以我宁愿避免这种情况。
有什么想法?
您可以使用Type-erase,因为正如Sean父母所说,继承是所有邪恶的基础。他还具有基于概念的多态性语义和基于概念的多态性,这可能是您想要的。这是相同的想法,例如std::function
。
基本上,您通过内部类中的继承使用子类型多态性,以将所有这些映射到概念多态态的所有内容。这是带有合并概念的类型擦除的示例:
class Greeter {
public:
// Constructor: We can stuff anything into a Greeter costume.
template <class T>
Greeter(T data) : self_(std::make_shared<Model<T>>(data)) {}
// External interface: Just forward the call to the wrapped object.
void greet(const std::string &name) const {
self_->greet(name);
}
private:
// The abstract base class is hidden under the covers...
struct Concept {
virtual ~Concept() = default;
virtual void greet(const std::string &) const = 0;
};
// ... and so are the templates.
template <class T>
class Model : public Concept {
public:
Model(T data) : data_(data) {}
virtual void greet(const std::string &name) const override {
// Forward call to user type.
// Requires that T can greet.
data_.greet(name);
}
private:
// The user defined Greeter will be stored here. (by value!)
T data_;
};
// Polymorphic types require dynamic storage.
// Here we store our pointer to the Model that holds the users Greeter.
std::shared_ptr<const Concept> self_;
};
现在,您可以将所有内容都放入具有问候方法的迎接器对象中。其他示例是boost :: any_iterator或std :: function。
您将遭受每个测量值的记忆分配。
您可以使用带有适当复制构建器的包装类别和指针作为字段。您可能需要添加克隆方法进行测量。
class MeasureWrapper
{
public:
MeasureWrapper(const MeasureWrapper &measureToCopy)
{
m_measure = measureToCopy.m_measure->Clone();
}
MeasureWrapper(Measure *measure) : m_measure(measure)
{
}
~MeasureWrapper()
{
delete m_measure;
}
// Wrap Measure interface here and call m_measure methods...
private:
Measure *m_measure;
};
您可以为此使用变体类型:它避免了动态分配,但是使多态性调度更为复杂。
请参阅boost.variant,希望有一个标准版本。
另外,您可以编写一个更具体的区分联合,提供一个很好的特定多态性界面