2017-10-10 58 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