2017-10-10 134 views
3

有几次我偶然发现了需要复制的指针容器。C++如何正确地复制指针的容器(向量)?

比方说,我们有下面的类层次结构:

  • 学生(基类)

    • 大一(子类)
    • Sophmore(子类)
    • 少年(子类)
    • 高级(小类)
  • StudentService

的StudentService类有一个std::vector<Student*> students场和下面的构造:

StudentService::StudentService(std::vector<Student*> students) { 
    // code 
} 

这不会是正确的,只是使用std::vector::operator=操作和写this->students = students,因为只会复制指针地址,所以如果外部的某个人删除了这些指针所指向的对象,那么StudentService类就会因此受到影响。

解决的办法是遍历在students参数每个指针,并创建一个新的动态对象,像这样:

for(int i = 0; i < students.size(); i++) { 
    this->students.at(i) = new Student(*students.at(i)); 
} 

但即使是不正确的,由于事实,即它只能建立学生对象。我们知道一个学生可以成为新生,Sophmore,初中或高中。所以这是我的问题:什么是这个问题的最佳解决方案?

我想一个办法是将每个学生类中的私有枚举场,并有4 if-else语句检查它是什么类型的学生,然后创建一个基于像这样一个新的动态对象:

for(int i = 0; i < students.size(); i++) { 
    if(students.at(i).getType() == FRESHMAN) { 
     this->students.at(i) = new Freshman(*students.at(i)); 
    } else if(students.at(i).getType() == SOPHMORE) { 
     this->students.at(i) = new Sophmore(*students.at(i)); 
    } else if { 
    // and so on... 
    } 
} 

但是,这仍然看起来很繁琐,所以你会建议什么?

+2

忘记载体。你将如何从'Student'指针创建一个'Freshman'?这是您需要在SO上搜索的问题。 – juanchopanza

+0

http://www.boost.org/doc/libs/1_65_1/doc/html/poly_collection.html –

+0

由于学生在不同的地方被“使用”,学生是否在你的大学克隆? – 2017-10-10 15:39:38

回答

7

您正在寻找克隆模式。 向学生添加一个clone()虚函数,该函数在每个后代中被覆盖并创建适当的副本。然后按照您正确指定的方式编写容器的深层副本。

编辑:我的工作假设是,你的大一学生等是从学生的下降。如果不是,请使用变体<>并应用副本访问者。

+0

这是一个很好的示例https://stackoverflow.com/questions/5148706/copying-a-polymorphic-object-in-c –

+1

谢谢!这正是我所需要的。 –

4

解决所有权问题

如果你认为你的模块之间共享的Student -s,那么你面临的所有权问题,我会建议使用的std::shared_ptr<Student> -s矢量来解决它。

如果你有std::vector<std::shared_ptr<Student>>,你可以将它传递给你想要的任何人。接收者可以使用赋值运算符复制vector,稍后他添加/删除的任何对象都不会影响原始容器,就像您似乎期望的那样。

解决问题克隆

如果您有兴趣每个模块有自己的一个Student的副本-s载体,你所面临的克隆问题。

您可以通过添加下面的方法到类解决这个问题:

class Student { 
    [..] 
    virtual Student * clone() const = 0; // Assuming Student is abstract, otherwise implement as well 
}; 

class Freshman : public Student { 
    [..] 
    virtual Freshman * clone() const { return new Freshman(*this); } 
}; 

// Same for other derived classes... 

,然后使用std::transform复制的载体:

// students is the original std::vector<Student *> 
std::vector<Student *> copy(students.size()); 
std::transform(students.begin(), students.end(), copy.begin(), [](Student * s) -> Student * { return s->clone(); }); 

顺便说一句,这是大二,不Sophmore .. 。

+2

我不认为这是OP想要的。当我相信OP需要深度复制时,使用'std :: shared_ptr'会给你一个浅的副本。 – NathanOliver

+2

根据OP的说法,@NathanOliver说:“因为那只会复制指针地址,所以如果外部的人删除了这些指针指向的对象,那么StudentService类就会因此而受到影响。”这绝对可以防止它。 –

+0

是的,它使它安全,但现在这两个向量仍然指向同一个对象。我相信OP希望两个矢量都有自己指向的对象。 – NathanOliver