struct Base {
virtual ~Base();
virtual std::auto_ptr<Base> clone(/*desired parameters, if any*/) const = 0;
};
这做了一些稍微不同的事情:克隆当前对象。这通常是您想要的,并允许您将对象作为模板保存,然后根据需要克隆和修改。 在Tronic上扩展,您甚至可以generateclone function。 为什么要使用 auto_ptr?这样你就可以使用 new 来分配对象,使所有权的转移显式化,并且调用者确信 delete 必须释放它。例如:
Base& obj = *ptr_to_some_derived;
{ // since you can get a raw pointer, you have not committed to anything
// except that you might have to type ".release()"
Base* must_free_me = obj.clone().release();
delete must_free_me;
}
{ // smart pointer types can automatically work with auto_ptr
// (of course not all do, you can still use release() for them)
boost::shared_ptr<Base> p1 (obj.clone());
auto_ptr<Base> p2 (obj.clone());
other_smart_ptr<Base> p3 (obj.clone().release());
}
{ // automatically clean up temporary clones
// not needed often, but impossible without returning a smart pointer
obj.clone()->do_something();
}
对象工厂
如果您希望完全按照要求执行并获得可以独立于示例使用的工厂:
struct Factory {}; // give this type an ability to make your objects
struct Base {
virtual ~Base();
virtual Factory get_factory() const = 0; // implement in each derived class
// to return a factory that can make the derived class
// you may want to use a return type of std::auto_ptr<Factory> too, and
// then use Factory as a base class
};
// Base class has a pure virtual function for cloning
class Shape {
public:
virtual ~Shape() {} // Polymorphic destructor to allow deletion via Shape*
virtual Shape* clone() const = 0; // Polymorphic copy constructor
};
// This CRTP class implements clone() for Derived
template <typename Derived> class Shape_CRTP: public Shape {
public:
Shape* clone() const {
return new Derived(dynamic_cast<Derived const&>(*this));
}
};
// Every derived class inherits from Shape_CRTP instead of Shape
// Note: clone() needs not to be defined in each
class Square: public Shape_CRTP<Square> {};
class Circle: public Shape_CRTP<Circle> {};
// Now you can clone shapes:
int main() {
Shape* s = new Square();
Shape* s2 = s->clone();
delete s2;
delete s;
}
struct Base { virtual Base* clone() const=0; }
struct Foo : public Base { Foo* clone() const { return new Foo(*this); }
struct Bar : public Base { Bar* clone() const { return new Bar(*this); }
Base * newObjectOfSameType( Base * b )
{
return b->clone();
}
class Base
{
public:
virtual ~Base() { }
};
class Foo : public Base
{
};
class Bar : public Base
{
};
template<typename T1, typename T2>
T1* fun(T1* obj)
{
T2* temp = new T2();
return temp;
}
int main()
{
Base* b = new Foo();
fun<Base,Foo>(b);
}
8条答案
按热度按时间ipakzgxi1#
克隆方法
查询类型的语言并没有提供任何东西,让你从这些信息中构造,但是你可以通过各种方式为你的类层次结构提供能力,其中最简单的是使用虚方法:
这做了一些稍微不同的事情:克隆当前对象。这通常是您想要的,并允许您将对象作为模板保存,然后根据需要克隆和修改。
在Tronic上扩展,您甚至可以generateclone function。
为什么要使用 auto_ptr?这样你就可以使用 new 来分配对象,使所有权的转移显式化,并且调用者确信 delete 必须释放它。例如:
对象工厂
如果您希望完全按照要求执行并获得可以独立于示例使用的工厂:
大部分相同的逻辑和功能可以用于克隆方法,因为 get_factory 完成了一半相同的角色,而返回类型(及其含义)是唯一的区别。
我也已经介绍过工厂几次了,你可以修改我的SimpleFactory class,让你的工厂对象(由 get_factory 返回)包含一个全局工厂的引用,加上要传递的创建参数(例如,类的注册名称-考虑如何应用 boost::function 和 boost::bind 来使其易于使用)。
rta7y2nd2#
通过基类创建对象副本的常用方法是添加一个clone方法,它本质上是一个多态复制构造函数。这个虚函数通常需要在每个派生类中定义,但是你可以通过使用Curiously Recurring Template Pattern来避免一些复制和粘贴:
请注意,你可以使用相同的CRTP类来实现任何功能,这些功能在每个派生类中都是相同的,但需要知道派生类型。除了clone()之外,还有许多其他用途,例如双重分派。
8ehkhllq3#
做这件事只有几种方法。
第一个和最丑的是:
请注意,只有当您启用了RTTI并且Base包含一些虚函数时,这才有效。
第二个更简洁的版本是向基类添加一个纯虚拟克隆函数
这样更整洁。
一个很酷/有趣的事情是
Foo::clone
返回Foo*
,而Bar::clone
返回Bar*
。你可能会认为这会破坏一些东西,但由于C++的一个称为协变返回类型的特性,一切都正常。不幸的是,协变返回类型不适用于智能指针,因此使用
sharted_ptrs
,您的代码将如下所示。eiee3dmh4#
你可以使用
typeid
来查询一个对象的动态类型,但是我不知道一种直接从类型信息示例化一个新对象的方法。但是,除了上面提到的
clone
方法之外,您还可以使用工厂:P.S.:这个代码示例的核心部分当然是
Factory::createFrom
方法。(这可能不是最漂亮的C代码,因为我的C已经有点生疏了。仔细想想,工厂方法可能不应该是静态的。)biswetbf5#
我在我的项目中使用了宏来合成这样的方法。我现在正在研究这种方法,所以我可能是错的,但是在我的IAllocable.hh代码中有一个问题的答案。注意,我使用GCC 4.8,但是我希望4.7适合。
使用方法:
希望有帮助。
s6fujrry6#
在C++中,是否有任何方法可以查询对象的类型...
是,使用
typeid()
运算符例如:
输出:
如果类型typeid计算的值是一个前面带有取消引用运算符(*)的指针,并且此指针具有空值,则typeid将引发bad_typeid异常
读取more.....
yvt65v4c7#
jv4diomz8#
当有非常多的类从同一个基类派生时,这段代码将使你不必在每个类中包含克隆方法。这是一种更方便的克隆方法,涉及模板和中间子类。如果层次结构足够浅,这是可行的。