Search code examples
c++pure-virtual

Implement pure virtual function with using


Consider the following program

class Node {
public:
  virtual void Visit() = 0;
};

class Graph {
public:
  virtual void Visit();
};

class GraphNode1 : public Node, Graph {
};

class GraphNode2 : public Node, Graph {
    using Graph::Visit;
};

class GraphNode3 : public Node, Graph {
public:
    virtual void Visit() {
        Graph::Visit();
    }
};

int main()
{
  GraphNode1 a;
  GraphNode2 b;
  GraphNode3 c;
}

It does not compile, but complains that GraphNode1 and GraphNode2 are abstract, since Node::Visit is pure virtual.

I would have assumed that both GraphNode1 and GraphNode2 were fine, since:

  • They contain an implementation of Visit.
  • They contain only a single implementation of Visit, so there should be no ambiguity.

Can anyone explain why I have to create an explicit implementation to make it work.


Solution

  • Node and Graph are unrelated classes. Which makes Node::Visit and Graph::Visit distinct unrelated member functions.

    Neither can override the other. You seem to think Graph::Visit is somehow "better" than Node::Visit on account of not being pure virtual, and should therefore override it. But there is no objective reason for it. For starters, pure virtual functions can have a definition:

    struct A {
        virtual void thing() = 0;
    };
    
    inline void A::thing() {}
    

    And secondly, a function can be made pure virtual when overriden:

    struct A {
        virtual void thing() {}
    };
    
    struct B : A {
        void thing() override = 0;
    };
    

    So really, there is no reason for Node::Visit and Graph::Visit to interact as overriders of each other. That's why you need to be explicit and define a function yourslef that will serve as an overrider*.


    * One shortcoming of C++ is that you in fact override both Node::Visit and Graph::Visit in GraphNode3. IMO it's a quirk of the language (really, it should be possible to keep them unrelated). MSVC has an extension that lets you choose what to override in a more fine-grained manner.