quetzalfir
quetzalfir

Reputation: 568

Constructor for class must explicitly initialize the base class

I've got:

//all classes are in different files
namespace Tree {
    class Node {
        NodeType type;
    protected:
        std::string nodename;
        Node(Node::NodeType _type) : type(_type) {}
    };
}

class Parent : public virtual Tree::Node {
protected:
    Parent() : Node(Node::UNDEFINED) {}
};

class Child: public virtual Tree::Node {
protected:
    Child() : Node(Node::UNDEFINED) {}
};

namespace Tree {
    class Element :
             public Parent,
             public Child,
             public virtual Node {

    protected:
        Element() : Node(Node::ELEMENT) {}
    };
}

class SpecificElement: public Tree::Element {
public:
    SpecificElement(const std::string name) {
        nodename = name;
    }
};

In the constructor of SpecificElement appears the error:

Constructor for 'SpecificElement' must explicitly initialize the base class 'Tree::Node' which does not have a default contructor

Isn't Node supposed to be initialized through Element?, why the compiler ask me for explicitly initialize there?

I don't know if this has anything to do with the builders being protected. Or if it is for the namespaces, although, I don't think so, since the code compiled, until I introduced the class SpecificElement.

I would call the constructor of Node in SpecificElement, but I have many more classes that inherit from this, and in all asks me to initialize explicitly Node, and I can not do that by design.

EDIT: thanks to @r-sahu, I solved it as follow

namespace Tree {
    class Node {
    protected:
        std::string nodename;
        NodeType type; //changed to protected

        Node(Node::NodeType _type) : type(_type) {}
        Node() : Node(UNDEFINED) {} //default constructor
    };
}

namespace Tree {
    class Element :
             public Parent,
             public Child,
             public virtual Node {

    protected:
        Element() { //change the init constructor list
            type = Node::ELEMENT; //change type inside constructor
        }
    };
}

Upvotes: 4

Views: 6242

Answers (1)

R Sahu
R Sahu

Reputation: 206567

Isn't Node supposed to be initialized through Element?, why the compiler ask me for explicitly initialize there?

No.

That happens only when you create an instance of Element, not a sub-class of Element. This has to do with virtual inheritance.

Classes that are virtually inherited must be initialized correctly in the constructor of the most derived class. Hence, you must use:

SpecificElement(const std::string name) : Tree::Node(Node::ELEMENT) {
    nodename = name;
}

With that in place, when you construct an instance of SpecificElement, the Tree::Node sub-object is initialized only once, from the constructo of SpecificElement. The Tree::Node(Node::Element) part in the constructor of Element is ignored at runtime.

The justification for this behavior can be found in the standard in Section 12.6.2 Initializing bases and members/10.1

Upvotes: 3

Related Questions