从现有实例中创建新的类实例一次
Create new class instances from existing once?
我得到了一个指向基类foo的指针向量,该基类有几个子类,我想做的是根据它是哪个子类,创建一个相同实例的新类。
我之前已经解决了这个问题,有一个巨大的for循环,它使用typeid来找出它是什么类,但没有更通用的方法来解决它吗?
基本上,像这样的东西就是我想要的:
std::vector<foo*> a;
std::vector<foo*> b;
//Store a couple of classes in a and b
b[0] = new typeid(a[0]).name();
一种方法是使用虚拟clone()
方法,该方法返回指向正确类型的对象的指针:
struct base
{
virtual base* clone()=0;
virtual ~base() {}
};
struct foo : public base
{
virtual base* clone() { return new foo(*this); }
};
struct bar : public base
{
virtual base* clone() { return new bar(*this); }
};
那么你的代码就是
b[0] = a[0].clone();
在现实生活中的代码中,您会返回一个智能指针,例如std::unique_ptr<base>
。
无论何时,只要您有一个基于类型的巨大开关,您可能都应该使用虚拟函数。
您应该引入某种虚拟clone()
函数:
#include <iostream>
#include <memory>
struct base
{
virtual ~base() {};
virtual void do_stuff() = 0;
// cloning interface
std::unique_ptr<base> clone() const
{
return std::unique_ptr<base>(do_clone());
}
private:
// actual clone implementation; uses a raw pointer to support covariance
virtual base* do_clone() const = 0;
};
struct derived_A : base
{
void do_stuff() override { std::cout << "stuff in derived_A" << std::endl; }
// purposefully hide the base implementation,
// since we know we'll be returning a derived_A
std::unique_ptr<derived_A> clone() const
{
return std::unique_ptr<derived_A>(do_clone());
}
private:
derived_A* do_clone() const override
{
return new derived_A(*this);
}
};
struct derived_B : base
{
void do_stuff() override { std::cout << "stuff in derived_B" << std::endl; }
// purposefully hide the base implementation,
// since we know we'll be returning a derived_B
std::unique_ptr<derived_B> clone() const
{
return std::unique_ptr<derived_B>(do_clone());
}
private:
derived_B* do_clone() const override
{
return new derived_B(*this);
}
};
#include <vector>
int main()
{
std::vector<std::unique_ptr<base>> v1;
std::vector<std::unique_ptr<base>> v2;
std::unique_ptr<base> x(new derived_A);
v1.push_back(std::move(x));
std::unique_ptr<base> y(new derived_B);
v1.push_back(std::move(y));
v1[0]->do_stuff();
v1[1]->do_stuff();
// clone
v2.push_back(v1[0]->clone());
v2.push_back(v1[1]->clone());
v2[0]->do_stuff();
v2[1]->do_stuff();
}
我们想要返回类型的协方差(如果您持有指向静态类型的derived_A
的指针,则克隆它应该会生成derived_A
以避免冗余强制转换),这就是为什么克隆接口被拆分为两部分的原因。如果std::unique_ptr<base>
与std::unique_ptr<derived>
协变,则可以在一个指针中完成,但这只是原始指针的情况。
我相信有一种方法可以隐藏重复的样板,这是读者的一个练习。
编辑:事实上,给你;不太难:
#include <memory>
// Note: leaves with a public: access specifier
#define DEFINE_ABSTRACT_CLONEABLE(selfType)
DEFINE_CLONEABLE_DETAIL(selfType)
private:
virtual selfType* do_clone() const = 0;
public:
// Note: leaves with a public: access specifier
#define DEFINE_CLONEABLE(selfType)
DEFINE_CLONEABLE_DETAIL(selfType)
private:
selfType* do_clone() const override
{
return new selfType(*this);
}
public:
#define DEFINE_CLONEABLE_DETAIL(selfType)
public:
std::unique_ptr<selfType> clone() const
{
static_assert(std::is_same<selfType,
std::decay<decltype(*this)>::type
>::value,
"Must specify current class name.");
return std::unique_ptr<selfType>(do_clone());
}
和测试(注意较小的尺寸):
#include <iostream>
#include "cloneable.hpp" // or whatever
struct base
{
// readable error: DEFINE_ABSTRACT_CLONEABLE(int);
DEFINE_ABSTRACT_CLONEABLE(base);
virtual ~base() {};
virtual void do_stuff() = 0;
};
struct derived_A : base
{
DEFINE_CLONEABLE(derived_A);
void do_stuff() override { std::cout << "stuff in derived_A" << std::endl; }
};
struct derived_B : base
{
// error: DEFINE_CLONEABLE(derived_B);
DEFINE_ABSTRACT_CLONEABLE(derived_B);
void do_stuff() override { std::cout << "stuff in derived_B" << std::endl; }
virtual void do_thing() = 0; // abstract again
};
struct derived_AA : derived_A
{
DEFINE_CLONEABLE(derived_AA);
void do_stuff() override { std::cout << "stuff in derived_AA" << std::endl; }
};
struct derived_BB : derived_B
{
DEFINE_CLONEABLE(derived_BB);
void do_stuff() override { std::cout << "doing stuff in derived_BB" << std::endl; }
void do_thing() override { std::cout << "doing thing" << std::endl; }
};
int main()
{
std::unique_ptr<derived_AA> x(new derived_AA());
x->do_stuff();
auto xx = x->clone();
xx->do_stuff();
std::unique_ptr<derived_A> xxx = xx->clone();
xxx->do_stuff();
std::unique_ptr<base> xxxx = xxx->clone();
xxxx->do_stuff();
xxxx->clone()->do_stuff();
std::unique_ptr<derived_BB> y(new derived_BB());
y->do_stuff();
y->do_thing();
auto yy = y->clone();
yy->do_stuff();
yy->do_thing();
std::unique_ptr<derived_B> yyy = yy->clone();
yyy->do_stuff();
yyy->do_thing();
std::unique_ptr<base> yyyy = yyy->clone();
yyyy->do_stuff();
// error, lost derived information: yyyy->do_thing();
yyyy->clone()->do_stuff();
}
另一个改进是使do_clone
的每个新声明都是纯虚拟的,以强制进一步的派生类实现它,但这个留给读者。
实现这一点的更好方法是使用dynamic_cast
。您可以尝试dynamic_cast
ing,然后调用相应的复制构造函数。话虽如此,我还是会选择clone
解决方案,或者尝试重新设计解决问题的方法。
例如,
child *c = dynamic_cast<child*>(base);
if(c != NULL) {
return new child(c);
}
相关文章:
- 我是否需要在下一次转移时将所有权*转移回转移队列
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 在C++中一次将矢量值写入多个文件
- 循环中的条件:为什么每次都调用strlen(),而vector.size()只调用一次
- 为什么 zlib 放气初始化调用一次不起作用?
- 在一次迭代中从 txt 文件中读取多行
- 为什么无论你输入什么,这"while(cin.get(str,3))"只运行一次?
- 在头文件和 cpp 文件中使用一次 #pragma 时出现结构重定义错误
- 有没有办法一次声明相同类型的多个对象,并通过一个表达式立即使用相同的右值初始化它们?
- 如何一次创建帧的一个实例
- 跨类的多个实例调用函数一次
- 一次运行程序的多个实例C
- 如何在返回一次数据后从类实例中删除数据
- 一次使用共享内存的多个实例
- 只实例化派生类一次错误的 OOP
- 如何使用C++单一实例返回仅初始化一次的对象
- 我可以检查哪些函数模板至少实例化过一次吗
- 一次只实例化一组类中的一个类,以节省内存
- 活动实例在JNI中每隔一秒改变一次
- 从现有实例中创建新的类实例一次