2016-07-22 129 views
0

我有一個類有一個std :: vector成員用於存儲外部類的對象。C++ - 通過成員函數更改一個類的成員值

class Example { 
    private: 
    std::vector<OtherClass> list_of_things_; 
} 

class OtherClass { 
    public: 
    void ChangeName(std::string name); 
    private: 
    std::string name_; 
} 

通過我的代碼,我想改變一些存儲在此list_of_things_的OtherClass的對象,所以我用我的例子類兩種功能:

std::vector<OtherClass> RetrieveObjects() { 
    std::vector<OtherClass> result; 
    std::vector<OtherClass>::iterator it; 
    for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) { 
    if (some condition is met) { 
     result.push_back(*it); 
    } 
    } 
} 

然後在實例中其他功能我打電話這個喜歡:現在

std::vector<OtherClass> objs = RetrieveObjects(); 
std::vector<OtherClass>::iterator it; 
for (it = objs.begin(); it != objs.end(); ++it) { 
    it->ChangeName("new name"); 
} 

,這是原則上的工作,但只有當我從OBJ文件變量檢查名字,這並沒有改變內部list_of_things_的對象是我的主要意圖。

我真的做了一個對象的副本,而不是檢索list_of_things_中的相同對象嗎?如果是這樣,爲什麼?我犯了一些其他錯誤嗎?我應該使用指針嗎?我是C++新手,仍然在尋找解決方法。

在這裏你可以找到一個運行測試代碼:

#include <vector> 
#include <string> 
#include <iostream> 

class OtherClass { 
    public: 
    OtherClass(std::string s) : name_(s) {} 
    std::string GetName(); 
    void ChangeName(std::string name); 
    private: 
    std::string name_; 
}; 

std::string OtherClass::GetName() { 
    return name_; 
} 

void OtherClass::ChangeName(std::string name) { 
    name_ = name; 
} 

class Example { 
    public: 
    Example(std::vector<OtherClass> l) : list_of_things_(l) {} 
    void ChangeNames(); 
    void WriteNames(); 
    protected: 
    std::vector<OtherClass> RetrieveObjects(); 
    private: 
    std::vector<OtherClass> list_of_things_; 
}; 

std::vector<OtherClass> Example::RetrieveObjects() { 
    std::vector<OtherClass> result; 
    std::vector<OtherClass>::iterator it; 
    for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) { 
    if (it->GetName() == "Name") { 
     result.push_back(*it); 
    } 
    } 
    return result; 
} 

void Example::ChangeNames() { 
    std::vector<OtherClass> objs = RetrieveObjects(); 
    std::vector<OtherClass>::iterator it; 
    for (it = objs.begin(); it != objs.end(); ++it) { 
    it->ChangeName("new name"); 
    std::cout << it->GetName() << std::endl; 
    } 
} 

void Example::WriteNames() { 
    std::vector<OtherClass>::iterator it; 
    for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) { 
    std::cout << it->GetName() << std::endl; 
    } 
} 

int main() { 
    OtherClass oc = OtherClass("Name"); 
    OtherClass oc2 = OtherClass("None"); 
    OtherClass oc3 = OtherClass("Name"); 

    std::vector<OtherClass> v = {oc, oc2, oc3}; 

    Example ex = Example(v); 
    ex.ChangeNames(); 
    ex.WriteNames(); 
} 

謝謝!

回答

3

您只能更改當地的objs載體,即副本載體的list_of_things_載體。既然你永遠不會把修改從副本寫回成員,當objs被銷燬時,它們會丟失。

解決這個問題是不是叫RetrieveObjectsChangeNames,而是直接在list_of_things_件上的最簡便方法:

void Example::ChangeNames() { 
    std::vector<OtherClass>::iterator it; 
    for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) { 
     it->ChangeName("new name"); 
     std::cout << it->GetName() << std::endl; 
    } 
} 

你得到副本的理由可以在RetrieveObjects簽名中找到:

std::vector<OtherClass> Example::RetrieveObjects() 

這裏的返回值是一個新的std::vector<OtherClass>對象。如果你不是要到一個現有的類對象的引用,簽名更改爲:

std::vector<OtherClass>& Example::RetrieveObjects() 

注意在返回值的額外&。這與C#和Java等語言不同,其中某些複雜類型總是按引用傳遞。

返回到成員矢量參考的RetrieveObjects的實現將是:

std::vector<OtherClass>& Example::RetrieveObjects() { 
    return list_of_things_; 
} 
+0

謝謝你的解釋! 如果我想要一個引用向量,我應該使用: std :: vector 與'&'裏面? – EDL

+0

@EDL引用的向量並不真的工作得很好,因爲引用是不可變的。在這種情況下,您最好使用指針向量:'std :: vector '。儘管指針在語法上比句柄要複雜得多,所以如果你不熟悉它們,你可能需要先做一些閱讀。 – ComicSansMS

0

它,它已經說過您修改向量的副本,這就是爲什麼你的主要載體保持不變。 如果您使用智能指針而不是簡單對象,則可以使用此方法。

typedef std::shared_ptr<OtherClass> OtherClassPtr; 

然後更換所有OtherClass用來OtherClassPtr讓你有 的std :: OtherClassPtr對象的載體,等等。你必須以不同的方式創建它們(std :: make_shared()),而不是。你使用 - > 但是,當你複製幾個對象並修改它們時,它們將在任何地方被修改,因爲你只複製指針。

0

我真的做了一個對象的副本,而不是檢索list_of_things_中的相同對象?

是的。您創建一個新的矢量,保存與您的選擇標準相匹配的原始值的副本。

如果是這樣,爲什麼?

std::vector<OtherClass> Example::RetrieveObjects() { // returns a new vector 
    std::vector<OtherClass> result; 
    std::vector<OtherClass>::iterator it; 
    for (it = list_of_things_.begin(); it != list_of_things_.end(); ++it) { 
    if (it->GetName() == "Name") { 
     result.push_back(*it); // The content of *it is copied to the new element of result. 
    } 
    } 
    return result; // do return a new vector, holding copies of originals 
} 

void Example::ChangeNames() { 
    std::vector<OtherClass> objs = RetrieveObjects(); // a local object with auto lifetime 
    std::vector<OtherClass>::iterator it; 
    for (it = objs.begin(); it != objs.end(); ++it) { 
    it->ChangeName("new name"); // acts on local object, class members are intact 
    std::cout << it->GetName() << std::endl; 
    } 
} // local object is gone with any changes it holds 

有我做了一些其他的錯誤嗎?我應該使用指針嗎?

,而不是試圖讓從list_of_things_第一,然後在選定的值進行一些操作基於標準的選擇,我會嘗試搜索,在一個通同時作用於原list_of_things_

相關問題