简体   繁体   中英

Child constructor uses grandparent constructor

I have the following class hierarchy with a virtual GrandParent and non-virtual Parent and Child :

class GrandParent {
protected:
    explicit GrandParent(const float &max_dur);
    virtual ~GrandParent() {}

private:
    const float _max_dur;
};

class Parent : public virtual GrandParent {
public:
    explicit Parent(const float &max_dur = 0);
};

class Child : public Parent {
public:
    explicit Child(const float &max_dur = 0);
};

Their constructors are nested like so:

// GrandParent constructor
GrandParent::GrandParent(const float &max_dur)
    : _max_dur{max_dur} {}

// Use GrandParent constructor
Parent::Parent(const float &max_dur)
    : GrandParent{max_dur} {}

// Use Parent constructor
Child::Child(const float &max_dur)
    : Parent{max_dur} {}                        // <- error occurs here

When I build, I get the following error message:

error: no matching function for call to ‘GrandParent::GrandParent()’

Codesnippet here .

It seems as if the Child constructor is ignored and it jumps to GrandParent instead. Modifying the Child constructor to directly call the GrandParent constructor (thus skipping a generation), I can bypass the error but it seems like the wrong approach.

Thanks in advance for your help!

Solution

Fixed by following 463035818-is-not-a-number's answer to call the GrandParent 's constructor explicitly and 康桓瑋's suggestion in order to call the Parent 's constructor as well:

Child::Child(const float &max_dur)
    : GrandParent{max_dur}, Parent{max_dur} {}

From the faq :

What special considerations do I need to know about when I inherit from a class that uses virtual inheritance?

Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor.

Because a virtual base class subobject occurs only once in an instance, there are special rules to make sure the virtual base class's constructor and destructor get called exactly once per instance. The C++ rules say that virtual base classes are constructed before all non-virtual base classes. The thing you as a programmer need to know is this: constructors for virtual base classes anywhere in your class's inheritance hierarchy are called by the “most derived” class's constructor.

The constructor of Child calls the constructor of GrandParent directly, because GrandParent is a virtual base. And because you did not call it explicitly, the default constuctor is called, but GrandParent has no default constructor.

Modifying the Child constructor to directly call the GrandParent constructor (thus skipping a generation), I can bypass the error but it seems like the wrong approach.

This is exactly the right approach. Child s constructor does call GrandParent s constructor, you cannot do anything about that when GrandParent is a virtual base and Child is the most-derived-class. What you can do is: Choose the right constructor instead of letting the compiler try to call the non-existent default constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM