C++ 从现有类实例创建新类实例一次?

C++ 从现有类实例创建新类实例一次?,c++,vector,C++,Vector,我得到了一个指向基类foo的指针向量,它有几个子类,我想做的是根据它是哪个子类,创建一个相同实例的新类 我在前面已经解决了这个问题,使用了一个巨大的for循环,它使用typeid来找出它是什么类,但是没有办法用更一般的方式来解决它吗 基本上,这就是我想要的: std::向量a; std::载体b; //在a和b中存储两个类 b[0]=新的typeid(a[0]).name(); 一种方法是使用虚拟的clone()方法返回指向正确类型对象的指针: struct base { virtual

我得到了一个指向基类foo的指针向量,它有几个子类,我想做的是根据它是哪个子类,创建一个相同实例的新类

我在前面已经解决了这个问题,使用了一个巨大的for循环,它使用typeid来找出它是什么类,但是没有办法用更一般的方式来解决它吗

基本上,这就是我想要的:

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
我相信有一种方法可以隐藏重复的样板文件,这是读者的练习。
:有什么有趣的提示吗