这个问题是关于复制和指针多态性的。考虑下面的代码。我们有两个类:Base和Derived,它们只是常规对象。然后我们有类Foo,它有一个指向Base作为其唯一成员的指针。
函数中描述了Foo的典型用法。main
输入Foo::SetMemberX
可能是也可能不是临时对象。
问题是我想Foo::SetMember
创建传递对象的正确副本,并将其地址分配为 a Base*
to Foo::mMember
。
我设法提出了 4 种可能的解决方案,但对我来说,这些解决方案都不是很优雅。前三个在下面的代码中显示在Foo::SetMember1
、Foo::SetMember2
和Foo::SetMember3
中。第四个选项是将内存分配留给用户(例如foo.SetMember(new Derived())
),这对于明显的内存安全问题来说不是很理想。Foo应该负责内存管理,而不是用户。
#include <iostream>
template <typename tBase, typename tPointer>
void ClonePointer(tBase*& destination, const tPointer* pointer)
{
destination = static_cast<tBase*>(new tPointer(*pointer));
}
// Base can be a virtual class
class Base
{
public:
virtual void Function()
{
std::cout << "Base::Function()" << std::endl;
}
virtual Base* Clone() const = 0;
};
class Derived : public Base
{
public:
virtual void Function()
{
std::cout << "Derived::Function()" << std::endl;
}
virtual Base* Clone() const
{
return new Derived(*this);
}
};
class Foo
{
public:
Foo() : mMember(NULL) { }
~Foo()
{
if (mMember != NULL)
{
delete mMember;
mMember = NULL;
}
}
template <typename T>
void SetMember1(const T& t)
{
if (mMember != NULL)
{
delete mMember;
mMember = NULL;
}
ClonePointer(mMember, &t);
}
void SetMember2(const Base& b)
{
mMember = b.Clone();
}
template <typename T>
void SetMember3(const T& t)
{
if (mMember != NULL)
{
delete mMember;
mMember = NULL;
}
mMember = new T(t);
}
Base& GetMember()
{
return *mMember;
}
private:
Base* mMember;
};
int main(int argc, char** argv)
{
{
Foo f1;
Foo f2;
Foo f3;
// The input may or may not be a tempoary/RValue reference
f1.SetMember1(Derived());
f2.SetMember2(Derived());
f3.SetMember3(Derived());
f1.GetMember().Function();
f2.GetMember().Function();
f3.GetMember().Function();
}
// Output:
// Derived::Function();
// Derived::Function();
// Derived::Function();
system("pause"); // for quick testing
}
第一种方法Foo::SetMember1
(
第二种方法 ( Foo::SetMember2
) 的问题是每个派生类都必须实现自己的Clone
功能。这对于类用户来说是太多的样板代码,因为会有很多类派生自Base。如果我可以以某种方式自动执行此操作,或者使用已实现的模板函数创建一个基本Cloneable类(每个Base派生类都不必显式调用它)Clone
,这将是理想的解决方案。
第三种方法 ( Foo::SetMember3
) 的问题是我需要Foo的模板访问器。这可能并不总是可行的,特别是因为在非模板类中不允许使用虚拟模板方法(Foo本身不能是模板),这是可能需要的功能。
我的问题是:
这些是我唯一的选择吗?
对于我缺少的这个问题,是否有更好、更优雅的解决方案?
有没有办法创建一个基本的Cloneable类并从中派生Base,并自动进行克隆
DerivedType::Clone()
?