You should totally use getters and setters. Copying the member once is a bad idea, because it leads to a copy which wouldn't update if the original changes. If you really need to have a reference to this object, you should better use std::shared_ptr instead.
If you are spending lots of time calling getters and setters, you should think about it, maybe this member should be in a class which uses this member variable. Maybe your class is doing to much stuff and the class which holds member functions which you access frequently needs to have a member function which would do the stuff with those variables!
For example, you may have a code like this:
if(someObject.getX() > y) {
someObject.setX(y);
}
Then maybe you can create a function which looks like this:
void SomeClass::changeXValue(Something& y) {
if(x > y) {
x = y;
}
}
If you can't find a way to do this and you can make some members public or make a Struct instead of Class.
For example, class Level changes tiles a lot, that's why I have struct Tile, so I can do stuff like this in the Level member functions:
tile.x = 10;
tile.y = 20;
I strongly recommend against using friend classes, they can lead to a code that is hard to change.
For example, before I introduced chunks in levels, I stored all tiles in one std::vector<std::vector>>
I have LevelEditor class which needs to change tiles a lot. I got tired of using stuff like this:
level->setTile(x, y, id);
So I've decided to make class LevelEditor a friend class for Level, so I could do stuff like this instead:
level->tiles[y][x] = id;
This was a bad idea, because when I've decided to store tiles in chunks, all tiles were not stored in one 2d array anymore! They were stored in N (N - number of chunks) 2d arrays!
So, every line of code which used tiles vector directly, didn't work anymore.
Some other classes used setTile function. So I only changed this function to work with chunks and not 2d array and every piece of code worked without any modifications. This was a pretty valuable lesson for me.