Reputation: 15
Sorry to post such a specific question, but I'm confused by an example question given in college. The question is:
class BoundingBox {
private:
float m_width;
float m_height;
public:
BoundingBox(float width = 0, float height = 0) :
m_width(width), m_height(height) {}
};
class Enemy {
private:
EnemyType m_type;
BoundingBox m_box;
Enemy(BoundingBox const & box, EnemyType type = EnemyType::Boss) :
m_type(type);
m_box(box);
{}
};
Q: Is the following construction of Enemy
legal? Explain.
Enemy enemy1(10);
The answer supplied says that it is, because the 10 is passed in as the width
parameter and the default is used for the height
, and also the default is used for the EnemyType
. But from my understanding, the line:
BoundingBox const & box
is expecting a box
object to be passed to it, not a parameter for it's constructor.
Has my lecturer made a mistake, or am I missing something? If I have misunderstood, could you provide me with a link that explains what is happening 'under the hood' so to speak. I didn't know this was a valid way to construct an object. I would ask my lecturer but he's been out sick for a week, and I can't find anything online about parameter based construction.
Upvotes: 1
Views: 51
Reputation: 30605
Yes, it is fine and will compile (barring the syntax and access to the constructor).
To create the type Enemy
, a BoundingBox
is required; in particular the Enemy
constructor accepts the argument as a const&
thus allowing temporary values to be used.
To create the BoundingBox
, no argument, one float
or two float
s can be used. The variation is because default arguments are supplied in the BoundingBox
constructor. The constructor is not marked explicit
(and this is the key bit that makes it work), the compiler is thus allowed to implicitly create the BoundingBox
temporary by itself - which it duly does and then creates the Enemy
object.
Adding an explicit
will result in a compilation failure; it would be constructive for you to do this, and observe the error messages you receive. I suspect this could the subject of future lectures as well.
In general and often, advice is given to mark constructors that could take a single argument (taking into account defaults) as explicit
thus preventing unknown (or unseen) conversions. If the implicit conversion is required, then don't add the explicit
.
Code with the syntax issues cleared up;
class BoundingBox {
private:
float m_width;
float m_height;
public:
/*explicit*/ BoundingBox(float width = 0, float height = 0) :
// ^^^^^^^ experiment with and without this being present
m_width(width), m_height(height) {}
};
class Enemy {
private:
EnemyType m_type;
BoundingBox m_box;
public:
// ^^^ added to allow access to the constructor
Enemy(BoundingBox const & box, EnemyType type = EnemyType::Boss) :
m_type(type),
// ^ syntax here
m_box(box)
// ^ syntax here
{}
};
Upvotes: 3