Weapon and Hero classes
This is a design issue, and there's no single answer.

We need to consider what's important about a Weapon.  Is it value-like, or is its identity important?  The real-world analogy is, "are copies all equivalent?".  The answer to this lies partly in the type, but also in how we intend to use it.

In the real world, Excalibur has an identity.  You can't copy it, but if you could, then each copy would have its own identity, and be owned by one person (let's ignore shared ownership, and losing it in the lake).  The same couldn't be said for the name (or the colour) of Excalibur - you can write the name as many times as you like, and they are all equal.  If you rename Excalibur to "a light-sabre", it doesn't change all the places you've written "Excalibur".

In cases where object identity is important, it's normal to delete the copy constructors and assignment operators:

class Weapon {
    // not copyable
    Weapon(const Weapon&amp;) = delete; // also removes Weapon(Weapon&amp;&amp;)
    Weapon&amp; operator=(const Weapon&amp;) = delete;

    // instance data
    std::string name;

public: 
    Weapon(std::string n = "rusty sword");
    ~Weapon();

    std::string getName();
};


Now we can't copy a Weapon.  We might be able to create another like it, but the two would be distinct.

Our hero needs to be assigned a Weapon.  Let's assume that giving Excalibur to Arthur means that he owns it, until it's destroyed or he gives it to someone else:

#include &lt;memory&gt;
class Hero {
    std::unique_ptr&lt;Weapon&gt; weapon;

public:
    void describeWeapon() {
      std::cout &lt;&lt; name &lt;&lt; " now swings " &lt;&lt; weapon-&gt;getName() &lt;&lt; std::endl;
    }
    void setWeapon(std::unique_ptr&lt;Weapon&gt;&amp;&amp; w) {
      weapon = std::move(w);
      describeWeapon();
    }
    ~Hero();
};


If the ownership is shared (perhaps it also belongs to a pool of weapons that secretly communicate with each other), then we'll want to use std::shared_ptr&lt;Weapon&gt; instead of a unique pointer.



One thing we need to be careful of is weapon-&gt;getName() in the code above.  If we're using pointers rather than objects or references, we'll need to be aware that we could be passed a null pointer.  We can specify that callers must not pass us null pointers, but calling code is notorious for forgetting such contracts.  An alternative is the Null Object pattern, where we create a no-effect weapon to stand in place of the null pointer.

We can arrange that like this:

class Hero {
    std::string name;
    const std::shared_ptr&lt;Weapon&gt; no_weapon
        = std::make_shared&lt;Weapon&gt;(name + "'s bare hands");
    std::shared_ptr&lt;Weapon&gt; weapon = no_weapon;

public:
    Hero(std::string n)
        : name(n)
    {
        std::cout &lt;&lt; "hero '" &lt;&lt; name &lt;&lt; "' constructed" &lt;&lt; std::endl;
        describeWeapon();
    }

    void describeWeapon()
    {
        std::cout &lt;&lt; name &lt;&lt; " now swings " &lt;&lt; weapon-&gt;getName() &lt;&lt; std::endl;
    }

    void setWeapon(const std::shared_ptr&lt;Weapon&gt;&amp; w)
    {
        weapon = w ? w : no_weapon;
        describeWeapon();
    }
    ~Hero()
    {
        std::cout &lt;&lt; "hero '" &lt;&lt; name &lt;&lt; "' destroyed" &lt;&lt; std::endl;
    }
};




A further consideration, that's specific to C++: the constructors that take a single argument are candidates for conversions.  You could have written:

Hero h = "Arthur";
h.setWeapon("The Holy Hand Grenade of Antioch");


and those strings would be converted to new objects.  We don't want that to happen, so we should probably declare the constructors explicit.