For me as a complete newbie to the world of C++, getters and setters are a rather confusing topic. There seems to be a wide range of opinions on what constitutes a sound use of getters and setters. In this particular post I'm most interested in finding a good way of using getters and setters in a memory-safe way.
I hacked up a little example. Consider this epic tale of a king and his magic sword:
#include <iostream>
#include <string>
using std::string;
class Weapon {
private:
string name;
public:
Weapon(string n = "rusty sword") : name(n) {
std::cout << "weapon '" << name << "' constructed" << std::endl;
}
string getName(){
return name;
}
~Weapon(){
std::cout << "weapon '" << name << "' destroyed" << std::endl;
}
};
class Hero {
private:
string name;
Weapon weapon;
public:
Hero(string n) : name(n) {
std::cout << "hero '" << name << "' constructed" << std::endl;
describeWeapon();
}
void describeWeapon() {
std::cout << name << " now swings " << weapon.getName() << std::endl;
}
void setWeapon(Weapon w) {
weapon = w;
describeWeapon();
}
~Hero() {
std::cout << "hero '" << name << "' destroyed" << std::endl;
}
};
int main() {
Hero h = Hero("Arthur");
Weapon ex = Weapon("Excalibur");
h.setWeapon(ex);
std::cout << "Ok, now all objects will go out of scope" << std::endl;
return 0;
}
This code yields the following output:
// our hero is given a rather modest sword to start with
weapon 'rusty sword' constructed
hero 'Arthur' constructed
Arthur now swings rusty sword
// Excalibur is created in the main scope
weapon 'Excalibur' constructed
Arthur now swings Excalibur // since we passed the object by value, Arthur now actually owns a COPY of the original Excalibur.
weapon 'Excalibur' destroyed // This is strange! Who got destroyed here?
Ok, now all objects will go out of scope
weapon 'Excalibur' destroyed // Here, Arthurs copy is being destroyed.
hero 'Arthur' destroyed // Arthur himself bites the dust.
weapon 'Excalibur' destroyed // And finally, the original sword leaves this world.
Now, there are a few obvious problems in this piece of code:
- For one, it is not ideal that we have the original Excalibur in the main-scope, while Arthur is only passed a copy. But what would be a better solution? Passing a pointer to Excalibur comes to mind, but is that the right way to go here?
- It also seems like just overwriting Arthur's old weapon with the new one passed in the setter causes some erratic behaviour. Consider the last line in the second paragraph of the output: here, allegedly Excalibur gets destroyed, while I believe that it is much rather the rusty old sword that Arthur owned originally that gets demolished.
The vast majority of literature about getters and setters deals with primitives, so any help on best practices for passing objects (or pointers or references to objects) into setters would be highly appreciated!
std::string
. It's appropriate to copy the name by value (if one of the names is destroyed, the others are unhurt). \$\endgroup\$ – Toby Speight Dec 14 '17 at 17:25std::string
constructor and the destructor! BTW, I'm only in Scotland by choice, not by birth... \$\endgroup\$ – Toby Speight Dec 14 '17 at 18:08