C++ 从现有类实例创建新类实例一次?
我得到了一个指向基类foo的指针向量,它有几个子类,我想做的是根据它是哪个子类,创建一个相同实例的新类 我在前面已经解决了这个问题,使用了一个巨大的for循环,它使用typeid来找出它是什么类,但是没有办法用更一般的方式来解决它吗 基本上,这就是我想要的:C++ 从现有类实例创建新类实例一次?,c++,vector,C++,Vector,我得到了一个指向基类foo的指针向量,它有几个子类,我想做的是根据它是哪个子类,创建一个相同实例的新类 我在前面已经解决了这个问题,使用了一个巨大的for循环,它使用typeid来找出它是什么类,但是没有办法用更一般的方式来解决它吗 基本上,这就是我想要的: std::向量a; std::载体b; //在a和b中存储两个类 b[0]=新的typeid(a[0]).name(); 一种方法是使用虚拟的clone()方法返回指向正确类型对象的指针: struct base { virtual
std::向量a;
std::载体b;
//在a和b中存储两个类
b[0]=新的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
一种方法是使用虚拟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\u ptr
更好的方法是使用dynamic\u cast
。您可以尝试dynamic\u cast
ing,然后调用相应的复制构造函数。话虽如此,我还是会选择克隆解决方案,或者尝试重新设计解决问题的方法
比如说,
child *c = dynamic_cast<child*>(base);
if(c != NULL) {
return new child(c);
}
child*c=dynamic_cast(基本);
如果(c!=NULL){
归还新子女(c);
}
更好的方法是使用dynamic\u cast
。您可以尝试dynamic\u cast
ing,然后调用相应的复制构造函数。话虽如此,我还是会选择克隆解决方案,或者尝试重新设计解决问题的方法
比如说,
child *c = dynamic_cast<child*>(base);
if(c != NULL) {
return new child(c);
}
child*c=dynamic_cast(基本);
如果(c!=NULL){
归还新子女(c);
}
每当您有一个基于类型的大型交换机时,您可能应该改用虚拟函数
您应该引入某种虚拟的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();
}
和测试(注意较小的尺寸):
#包括
#包括“cloneable.hpp”//或其他内容
结构基
{
//可读错误:定义抽象可克隆(int);
定义抽象可克隆(基本);
虚~base(){};
虚拟void do_stuff()=0;
};
结构派生_A:base
{
定义可克隆的(派生的);
void do_stuff()重写{std::cout do_stuff();
y->do_thing();
自动yy=y->clone();
yy->do_stuff();
yy->do_thing();
std::unique_ptr yyy=yy->clone();
yyy->do_stuff();
yyy->do_thing();
std::unique_ptr yyyy=yyy->clone();
yyyy->do_stuff();
//错误,丢失派生信息:yyyy->do_thing();
yyyy->clone()->do_stuff();
}
另一个改进是使每个新的
do\u clone
声明都是纯虚拟的,以强制进一步的派生类来实现它,但这是留给读者的。每当您有一个基于类型的巨大开关时,您可能应该使用虚拟函数
您应该引入某种虚拟的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();
}
和测试(注意较小的尺寸):
#包括
#包括“cloneable.hpp”//或其他内容
结构基
{
//可读错误:定义抽象可克隆(int);
定义抽象可克隆(基本);
虚~base(){};
虚拟void do_stuff()=0;
};
结构派生_A:base
{
定义可克隆的(派生的);
void do_stuff()重写{std::cout do_stuff();
y->do_thing();
自动yy=y->clone();
yy->do_stuff();
yy->do_thing();
std::unique_ptr yyy=yy->clone();
yyy->do_stuff();
yyy->do_thing();
std::unique_ptr yyyy=yyy->clone();
yyyy->do_stuff();
//错误,丢失派生信息:yyyy->do_thing();
yyyy->clone()->do_stuff();
}
另一个改进是使
do\u clone
的每一个新声明都是纯虚拟的,以强制进一步的派生类来实现它,但这是留给读者的。这是如何工作的?你能提供一些代码吗?用dynamic\u cast
替换你的typeid
,然后检查它不是NULL
。嗯?repl用dynamic_cast替换typeid会导致它无法编译?我不是说字面意思!我能想到的唯一方法是对所有不同的选项进行dynamic cast…然后在dynamic cast不返回null的类上执行new,但这太糟糕了!每次在层次结构中添加一个新类时,都需要向该condi添加一个分支事实上,dynamic\u cast在这里并不能很好地工作。它是如何工作的?你能提供一些代码吗?用dynamic\u cast
替换你的typeid
,然后检查它是否为NULL
。哈?用dynamic\u cast替换typeid会导致它无法编译吗?我不是说真的!我能想到的唯一方法就是动态amic cast对所有不同的选项进行转换…然后在动态转换不返回null的类上执行新操作,但这太糟糕了!每次在层次结构中添加新类时,都需要向该条件添加一个分支。事实上,动态转换在这里并不能很好地工作。+1注意std::unique\ptr
是从Hm,实际上任何类型的智能指针都不会与标准容器(在原始问题中假设)的常规实现发生冲突吗?@peterph不,只要智能指针不是弃用的std::auto_ptr
+1,并注意到std::unique_ptr
是因为C++11 only.Hm,实际上任何类型的智能指针都不会与标准容器的常规实现发生冲突(在原始问题中假设)?@peterph不,只要智能指针不是弃用的std::auto_ptr
我相信有一种方法可以隐藏重复的样板文件,这是读者的练习。
:有什么有趣的提示吗