我想实现类,让我们说有字段键和类A或B. 此类中构造函数中的参数是字符数组。 构造函数伪代码将查看第一个char,如果它是exto到0x00,它将创建A类对象, 否则它将创建B类对象 - 两个类都将chars数组作为参数。
无论如何,我想保持这个实现简单。除非我真的需要,否则我不想使用boost :: Variant, 而且我也不想像这样实施Implementing a "variant" class 因为我不熟悉模板编程,我认为我的问题可以用更简单的方式实现。
答案 0 :(得分:2)
对于POD类型,我们有union
(但联盟将不记得您指定的类型,因此也单独存储)。这不适用于非POD类型。主要原因是因为C ++在删除联合时不知道应该在构造/删除时创建哪一个。
但联盟可用于保存指向实际类型的指针。然后你必须自己关心构造和删除。
你可以创建这样的东西,它包装了这个指针联合并添加了一个方便的界面。详细解释写在评论中:
class EitherAorB {
// We have to remember what we actually created:
enum Which {
A_Type,
B_Type
} m_which;
// We store either a pointer to an A or to a B. Note that this union only
// stores one pointer which is reused to interpret it as an A*, B* or void*:
union {
A *a;
B *b;
void *untyped; // Accessing the same pointer without looking at the type
} m_ptr;
// Additional stuff you want to store besides A and B
const char *m_key;
public:
EitherAorB(const char *key) {
// Decision: Which type do we want to create?
m_which = key[0] == 0 ? A_Type : B_Type;
// Create the type (the cast to void* make the pointer "untyped"):
m_ptr.untyped = m_which == A_Type ? (void*)new A() : (void*)new B();
// Store additional stuff
m_key = key;
}
~EitherAorB() {
// Since we stored the actual contents outside and point to them,
// we have to free the memory. For this, we have to care about the
// type again, so the correct destructor will be chosen. Deleting
// the untyped pointer won't work here.
if (m_which == A_Type) delete m_ptr.a;
if (m_which == B_Type) delete m_ptr.b;
}
// These two functions can be used to query which type is stored.
bool hasA() const {
return m_which == A_Type;
}
bool hasB() const {
return m_which == B_Type;
}
// These two functions can be used to query the pointers to the actual types.
// I made them return a null pointer if the wrong getter was used.
A *getA() {
return m_which == A_Type ? m_ptr.a : 0;
}
B *getB() {
return m_which == B_Type ? m_ptr.b : 0;
}
}
请注意,如果复制EitherAorB
的实例,此实现将缺少内存。要解决此问题,请禁用复制(通过使复制构造函数和赋值运算符为私有或使用= delete
在C ++ 11中禁用它们),或者实现将深深复制指针对象的复制构造函数和赋值运算符。
你说你不熟悉模板编程。使这种实现模板化并不困难。只需将template<typename A, typename B>
放在整个类定义之前;它应该开箱即用。但是,在这种情况下,请勿移动.cpp
文件中的实现;最好是在我写这篇文章时让它们内联。
然后,A
和B
不是类型,而是您在客户端代码中指定类型的占位符。然后我将tempalte类重命名为Either
,因此您的类型名称变为类似Either<This, That>
。