是的,有可能,但是当然必须有一些隐藏指针,而且实际数据必须存储在堆上。原因是在编译时无法知道数据的实际大小,因此无法在堆栈上。
这个想法是通过一个多态类的指针来存储实际的实现ValueImpl
,它提供了你需要的任何虚拟方法,比如increments()
or print()
,另外还有一个方法clone()
,这样你的类Data
就能够实现值语义:
class ValueImpl
{
public:
virtual ~ValueImpl() {};
virtual std::unique_ptr<ValueImpl> clone() const { return new ValueImpl(); }
virtual void increments() {}
virtual void print() const { std::cout << "VoidValue "; }
};
class Value
{
private:
ValueImpl * p_; // The underlying pointer
public:
// Default constructor, allocating a "void" value
Value() : p_(new ValueImpl) {}
// Construct a Value given an actual implementation:
// This allocates memory on the heap, hidden in clone()
// This memory is automatically deallocated by unique_ptr
Value(const ValueImpl & derived) : p_(derived.clone()) {}
// Destruct the data (unique_ptr automatically deallocates the memory)
~Value() {}
// Copy constructor and assignment operator:
// Implements a value semantics by allocating new memory
Value(const Value & other) : p_(other.p_->clone()) {}
Value & operator=(const Value & other)
{
if(&other != this)
{
p_ = std::move(other.p_->clone());
}
return *this;
}
// Custom "polymorphic" methods
void increments() { p_->increments(); }
void print() { p_->print(); }
};
包含的指针存储在 C++11std::unique_ptr<ValueImpl>
中,以确保在销毁或分配新值时释放内存。
派生的实现最终可以通过以下方式定义:
class IntValue : public ValueImpl
{
public:
IntValue(int k) : k_(k) {}
std::unique_ptr<IntValue> clone() const
{
return std::unique_ptr<IntValue>(new IntValue(k_));
}
void increments() { k_++; }
void print() const { std::cout << "Int(" << k_ << ") "; }
private:
int k_;
};
class DoubleValue : public ValueImpl
{
public:
DoubleValue(double x) : x_(x) {}
std::unique_ptr<DoubleValue> clone() const
{
return std::unique_ptr<DoubleValue>(new DoubleValue(k_));
}
void increments() { x_ += 1.0; }
void print() const { std::cout << "Double(" << x_ << ") "; }
private:
int x_;
};
这足以使问题中的代码片段无需任何修改即可工作。这提供了具有值语义的运行时多态性,而不是具有 C++ 语言内置的指针语义的传统运行时多态性。实际上,多态性的概念(根据其真实“类型”处理行为不同的通用对象)独立于指针的概念(能够通过使用对象的地址共享内存和优化函数调用),恕我直言更多的是实现细节,多态性仅通过 C++ 中的指针提供。上面的代码是在“哲学上不需要”使用指针时利用多态性的一种解决方法,从而简化了内存管理。
注意:感谢 CaptainObvlious 的贡献和他在此处提供的进化代码,我部分集成了这些代码。未集成的有:
- 为了简化派生实现的创建,您可能需要创建一个中间模板类
- 您可能更喜欢使用抽象接口而不是我的非抽象基类