2016-07-22 128 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_

相关问题