1

I am trying to understand how references work in c++ so I have make a couple files with two different objects. One is an animal and another is a zookeeper. My goal is to pass a reference of an animal to a zookeeper and have the zookeeper change the animal's name, and still be reflected in the original animal object. How is this done using references? Here are the files I'm using.

Source.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;
}

Animal.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; }
};

zookeeper.cpp

#include "zookeeper.h"

using namespace std;

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

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

zookeeper.h

#pragma once

#include "Animal.h"

class Zookeeper {
    Animal _myAnimal;
public:
    Zookeeper(Animal& a);
    void changeMyAnimalsName(std::string newName);
};
gsamaras
  • 71,951
  • 46
  • 188
  • 305
LucasN
  • 243
  • 1
  • 2
  • 14

2 Answers2

1

Your reasoning is correct, but you ended up making a copy of the animal, there:

class Zookeeper {
    Animal _myAnimal;

If you had:

Animal& _myAnimal;

then you would maintain the reference to the original animal, making possible for the name change to be reflected in main().

After that, you should change your constructor to this:

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

where I used an initializer list, which is essential for references, as you can read in How to initalize the reference member variable of a class?


However, this is not enough. If you had used -Wall -Wextra flag, to enable warnings you would see this:

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());
                                                                                       ^

In we usually print with std::cout, like this:

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

Or, if you really need to use printf(), then you could use c_str(), which returns a C-string of std::string, like this:

printf("animal's name before it is assigned to a zookeeper: %s\n", animal.getName().c_str());
gsamaras
  • 71,951
  • 46
  • 188
  • 305
0

Your class Zookeeper defines data member _myAnimal of type Animal (and not of type Animal&). Hence, if in your constructor you assign _myAnimal = a, then a - though being a reference - is copied because _myAnimal is not a reference. To keep the reference to the object passed to the constructor, you'd need to define data member _myAnimal as a reference, too:

class Zookeeper {
    Animal &_myAnimal;
public:
    Zookeeper(Animal& a) : _myAnimal(a) { };
    void changeMyAnimalsName(std::string newName);
};
Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • You also need to change how the member is initialized. See https://stackoverflow.com/questions/15403815/how-to-initalize-the-reference-member-variable-of-a-class – Barmar Jun 07 '17 at 21:43