C ++ - 通过成员函数更改类的成员值

时间:2016-07-22 12:29:29

标签: c++11

我有一个类,它有一个std :: vector成员,用于存储外部类的对象。

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对象,所以我在Example类中使用了两个函数:

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);
    }
  }
}

然后在Example中的另一个函数中,我将其称为:

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

现在,这原则上是有效的,但只有当我从objs变量中检查名称时,这才会改变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 个答案:

答案 0 :(得分:3)

您只对本地objs向量进行了更改,该向量是{em> list_of_things_向量的副本。由于您从未将副本中的更改写回成员,因此在objs被销毁时它们会丢失。

解决此问题的最简单方法是不要在RetrieveObjects内拨打ChangeNames,而是直接在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_;
}

答案 1 :(得分:0)

已经有人说你修改了矢量的副本,这就是你的主矢量保持不变的原因。 如果使用智能指针而不是简单对象,则可以使用此方法。

typedef std::shared_ptr<OtherClass> OtherClassPtr;

然后将所有OtherClass使用替换为OtherClassPtr以便您拥有 其他的ClassCtr对象的std :: vector,等等。你必须以不同的方式创建它们(std :: make_shared())而不是。你用 - &gt; 但是在你复制几个对象并修改它们之后,它们将被修改,因为你只复制指针。

答案 2 :(得分: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_