【问题标题】:How do I pass a reference of one object to another and still modify that first object?如何将一个对象的引用传递给另一个对象并仍然修改第一个对象?
【发布时间】:2017-06-07 21:37:00
【问题描述】:

我试图了解引用在 c++ 中是如何工作的,所以我制作了几个包含两个不同对象的文件。一个是动物,另一个是动物园管理员。我的目标是将动物的引用传递给动物园管理员并让动物园管理员更改动物的名称,并且仍然反映在原始动物对象中。这是如何使用引用完成的?这是我正在使用的文件。

源.cpp

#include <iostream>
#include <string>
#include "Animal.h"
#include "zookeeper.h"

using namespace std;

int main() {

    Animal animal;
    Animal& animalRef = animal;

    printf("animal's name before it is assigned to a zookeeper: %s\n", animal.getName());

    Zookeeper aZookeeper = Zookeeper(animalRef);
    aZookeeper.changeMyAnimalsName("Fred");

    printf("animal's name after it is assigned to a zookeeper: %s\n", animal.getName());

    //Keep cmd window open
    int j;
    cin >> j;
    return 0;
}

动物.h

#pragma once
#include <string>

using namespace std;

class Animal {

    string name = "";
    int height = 0;
public:
    string getName() { return name; }
    int getHeight() { return height; }

    void setName(string n) { name = n; }
    void setHeight(int h) { height = h; }
};

动物园管理员.cpp

#include "zookeeper.h"

using namespace std;

Zookeeper::Zookeeper(Animal& a) {
    _myAnimal = a;
}

void Zookeeper::changeMyAnimalsName(string newName) {
    _myAnimal.setName(newName);
}

动物园管理员.h

#pragma once

#include "Animal.h"

class Zookeeper {
    Animal _myAnimal;
public:
    Zookeeper(Animal& a);
    void changeMyAnimalsName(std::string newName);
};

【问题讨论】:

  • 引用与文件无关,所以如果你想研究它们是如何工作的,请将所有代码放在一个文件中。
  • Zookeeper 构造函数中执行_myAnimal = a; 时,您正在制作副本,因为_myAnimal 不是参考。
  • Animal&amp; _myAnimal;(注意与号)和Zookeeper::Zookeeper(Animal&amp; a) : _myAnimal(a) {}
  • @IgorTandetnik 把它放在一个答案中。
  • @Barmar 这是订单吗?

标签: c++ string function oop reference


【解决方案1】:

你的推理是正确的,但你最终制作了动物的副本,在那里:

class Zookeeper {
    Animal _myAnimal;

如果你有:

Animal& _myAnimal;

那么您将保留对原始动物的引用,从而使名称更改可以反映在 main() 中。

之后,您应该将构造函数更改为:

Zookeeper(Animal& a) : _myAnimal(a) {}

我使用了一个初始化列表,这对于引用至关重要,您可以在How to initalize the reference member variable of a class? 中阅读


但是,这还不够。如果您使用 -Wall -Wextra 标志来启用警告,您会看到:

Source.cc: In function 'int main()':
Source.cc:13:88: warning: format '%s' expects argument of type 'char*', but argument 2 has type 'std::__cxx11::string* {aka std::__cxx11::basic_string<char>*}' [-Wformat=]
     printf("animal's name before it is assigned to a zookeeper: %s\n", animal.getName());
                                                                                        ^
Source.cc:18:87: warning: format '%s' expects argument of type 'char*', but argument 2 has type 'std::__cxx11::string* {aka std::__cxx11::basic_string<char>*}' [-Wformat=]
     printf("animal's name after it is assigned to a zookeeper: %s\n", animal.getName());
                                                                                       ^

中,我们通常使用std::cout 打印,如下所示:

int main() {

    Animal animal;
    Animal& animalRef = animal; // not needed, Zookeeper(animal) OK too

    std::cout << "animal's name before it is assigned to a zookeeper: " << animal.getName() << std::endl;

    Zookeeper aZookeeper = Zookeeper(animalRef);
    aZookeeper.changeMyAnimalsName("Fred");

    std::cout << "animal's name after it is assigned to a zookeeper: " << animal.getName() << std::endl;
    return 0;
}

或者,如果你真的需要使用printf(),那么你可以使用c_str(),它返回一个std::string的C字符串,像这样:

printf("animal's name before it is assigned to a zookeeper: %s\n", animal.getName().c_str());

【讨论】:

    【解决方案2】:

    您的类Zookeeper 定义了Animal 类型的数据成员_myAnimal(而不是Animal&amp; 类型)。因此,如果您在构造函数中分配了_myAnimal = a,那么a(尽管是引用)会被复制,因为_myAnimal 不是引用。 要保留对传递给构造函数的对象的引用,您还需要将数据成员 _myAnimal 定义为引用:

    class Zookeeper {
        Animal &_myAnimal;
    public:
        Zookeeper(Animal& a) : _myAnimal(a) { };
        void changeMyAnimalsName(std::string newName);
    };
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-09-15
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 2015-06-14
    • 2021-09-23
    • 2023-03-24
    相关资源
    最近更新 更多