One thing to keep in mind is that if operator=
- or any function it calls - is virtual
, the derived-class version won't be invoked. This could result in uninitialised fields and later Undefined Behaviour, but it all depends on your data members.
More generally, your bases and data members are guaranteed to have been initialised if they have constructors or appear in the initialiser list (or with C++11 are assigned to in the class declaration) - so apart from the virtual
issue above, operator=
will often work without Undefined Behaviour.
If a base or member has been initialised before operator=()
is invoked, then the initial value is overwritten before it's used anyway, the optimiser may or may not be able to remove the first initialisation. For example:
std::string s_;
Q* p_;
int i_;
X(const X& rhs)
: p_(nullptr) // have to initialise as operator= will delete
{
// s_ is default initialised then assigned - optimiser may help
// i_ not initialised but if operator= sets without reading, all's good
*this = rhs;
}
As you can see, it's a bit error prone, and even if you get it right someone coming along later to update operator=
might not check for a constructor (ab)using it....
You could end up with infinite recursion leading to stack overflow if getWeapon()
uses the Prototype or Flyweight Patterns and tries to copy-construct the Weapon
it returns.
Taking a step back, there's the question of why getWeapon(CHAIN_GUN);
exists in that form. If we need a function that creates a weapon based on a weapon type, on the face of it a Weapon(Weapon_Type);
constructor seems a reasonable option. That said, there are rare but plentiful edge cases where getWeapon
might return something other than a Weapon
object that can never-the-less be assigned to a Weapon
, or might be kept separate for build/deployment reasons....