Comorbid
Comorbid

Reputation: 15

Confused by parameters example given in college lecture

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

Answers (1)

Niall
Niall

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 floats 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

Related Questions