修改类c++上的引用成员

Modify references members on class c++

本文关键字:引用 成员 c++ 修改      更新时间:2023-10-16

我是c++新手,来自Java。所以我对通过引用变量修改类成员有一些猜测。

在java中,向现有列表(类成员)添加元素只需要使用"add"方法,仅此而已,但在这里我不明白为什么我不能用get方法修改向量。

class Student {
public:
  Student(std::string n):name(n){};
  std::string getName(){return name;};
  void setName(std::string name){this->name = name;};
private:
  std::string name;
};
class Subject {
public:
  std::vector<Student> getStudents(){return students;};
  void setStudents(std::vector<Student> students){this->students = students;};
private:
  std::vector<Student> students;
};
int main() {
  // Students
  Student s1("Abi");
  Student s2("Nat");
  Student s3("Osi");
  // normal case
  Subject math;
  std::vector<Student> students;
  students.push_back(s1);
  math.setStudents(students);
  math.getStudents().push_back(s2);
  // print names
  for(unsigned int i=0; i < math.getStudents().size();i++) {
    std::cout << math.getStudents()[i].getName() << std::endl;
  }
  // pointers
  std::cout << "Ptr------------------" << std::endl;
  Subject *mathPtr;
  mathPtr  = &math;
  // try to add student to the existing vector
  mathPtr->getStudents().push_back(s2); // it doesnt work
  // it works if i add a new vector
  std::vector<Student> studentsPtr;
  studentsPtr = mathPtr->getStudents();
  studentsPtr.push_back(s2);
  mathPtr->setStudents(studentsPtr);
  // print students of original object
  for(unsigned int i=0; i < math.getStudents().size();i++) {
    std::cout << math.getStudents()[i].getName() << std::endl;
  }
  // pointers
  std::cout << "Smart_ptr-------------" << std::endl;
  std::shared_ptr<Subject> mathSmartPtr;
  mathSmartPtr  = std::make_shared<Subject>(math);
  // try to add student to the existing vector
  mathSmartPtr->getStudents().push_back(s3); //it  doesnt work
  std::vector<Student> studentsSmartPtr;
  studentsSmartPtr = mathPtr->getStudents();
  studentsSmartPtr.push_back(s3);
  mathSmartPtr->setStudents(studentsSmartPtr);// it doesnt work too
  // print students of original object
  for(unsigned int i=0; i < math.getStudents().size();i++) {
    std::cout << math.getStudents()[i].getName() << std::endl;
  }
}

我不明白为什么智能指针不起作用。它应该是一个普通指针+自动删除,不是吗?

问候和感谢。

您的代码中的问题是您在没有意识到的情况下对学生向量进行了大量复制。这是Java中常见的问题。

具体来说,在Subject类中,getStudents方法不会做你可能认为它会做的事情:

std::vector<Student> getStudents(){return students;};

它生成一个名为"students"的向量副本,并将副本返回给您,而不是原始副本。同样的情况也发生在代码的其他地方,但可能危害较小。

您可以通过包含参考运算符来轻松解决此问题:

std::vector<Student>& getStudents(){return students;};

将像在Java中一样工作。但也有一个危险:如果你的Subject对象被破坏了,向量就会随之而去——即使你在其他地方存储了对它的引用。例如,这可能会使您的程序崩溃:

Subject* mathPtr = new Subject;
// try to add student to the existing vector
std::vector<Student>& s = mathPtr->getStudents();
delete mathPtr;
s.push_back(s2); // accesses already-freed memory

您已声明getStudents以返回students向量的副本

std::vector<Student> getStudents(){return students;};

所以当你这样做的时候:

getStudents().push_back(...)

它只会添加到向量的副本中,该副本会立即被销毁,因为您没有将其存储在任何位置。因此,原始CCD_ 3矢量不会被修改。

如果要将push_back转换为原始矢量,则需要向其返回引用:

std::vector<Student>& getStudents(){return students;}; 
                    ^

这可能有助于

 class Student {
    public:
        Student(std::string n) :name(n){};
        std::string getName(){ return name; };
        void setName(std::string name){ this->name = name; };
    private:
        std::string name;
    };
    class Subject {
    public:
        Student * getStudent(std::string name);
        void setStudents(Student* student);
        void PrintStudents();
    private:
        std::vector<Student*> students;
        typedef std::vector<Student*>::iterator iter;
    };
    Student* Subject::getStudent(std::string name)
    {
        Student* stud = NULL;
        for (iter i = students.begin(); i != students.end(); ++i)
        {
            if ((*i)->getName() == name)
                stud = (*i);
        }
        return stud;
    }
    void Subject::setStudents(Student* student)
    {
        students.push_back(student);
    }
    void Subject::PrintStudents()
    {
        for (iter i = students.begin(); i != students.end(); ++i)
        {
                std::cout << (*i)->getName() << std::endl;
        }
    }
    int main()
    {
        Student* s1;
        s1 = new Student("Kavinda");
        Student s2("Liza");
        Subject math;
        math.setStudents(s1);
        math.setStudents(&s2);
        Student *s3 = math.getStudent("Kavinda");
        if (s3)
            std::cout << s3->getName() << std::endl;
        else
            std::cout << "No Student Exists having that namen" << std::endl;
        math.PrintStudents();
        getchar();
        return 0;
    }