Search code examples
c++inheritancevirtualabstractpure-virtual

cannot declare to be of abstract type


I got the following error:

error: cannot declare variable 'b' to be of abstract type 'B'
note: because the following virtual functions are pure within 'B'
note: virtual bool Serializable::eq(const QString&) const
      virtual bool eq( const QString & qs) const = 0;
                   ^
note: virtual bool Serializable::eq(const Serializable*) const
      virtual bool eq( const Serializable * o) const = 0;
                   ^

on this code:

class Serializable {
public:
    virtual  bool eq( const QString & qs) const = 0;
    virtual  bool eq( const Serializable * o) const = 0;
};

class JSONSerializable : public Serializable {
public:
    virtual  QString toJSON( void) const = 0;

    virtual  bool eq( const QString & qs) const {
                 return toJSON() == qs;
             }
    virtual  bool eq( const Serializable * o) const {
                 return eq( (( JSONSerializable *) o)->toJSON());
             }
};

class A : public Serializable {  };

class B : public A,
          public JSONSerializable {
public:
    virtual  QString toJSON( void) const {
                 return QString( "test!");
             }
};

…
B b;
qDebug() << b.toJSON();
…

I understand that it's because of the pure virtual methods or/and multiple inheritance. This error really makes me cry. How can I make it dissappear? I would be very appreciate for some help!


Solution

  • The problem is that B inherits the abstract class Serializable twice:

    • Once through its base class A, and
    • Once more through its other base class JSONSerializable

    As the result, you must override the two pure virtuals of Serializable twice.

    Since you are asking the question about B's remaining abstract, my understanding is that you did not intend things to be that way: you wanted B to inherit Serializable only once, as if it were an interface, and use JSONSerializable's implementation to "mix in" additional functionality. If that is the case, you need to inherit Serializable virtually, like this:

    class Serializable {
    public:
        virtual  bool eq( const QString & qs) const = 0;
        virtual  bool eq( const Serializable * o) const = 0;
    };
    
    class JSONSerializable : virtual public Serializable {
    public:
        virtual  QString toJSON( void) const = 0;
    
        virtual  bool eq( const string & qs) const {
                     return toJSON() == qs;
                 }
        virtual  bool eq( const Serializable * o) const {
                     return eq(dynamic_cast<const JSONSerializable*>(o)->toJSON());
                 }
    };
    
    class A : virtual public Serializable {  };
    
    class B : virtual public A,
              public JSONSerializable {
    public:
        virtual  QString toJSON( void) const {
                     return QString( "test!");
                 }
    };
    

    The added virtual keyword instructs the compiler that you want only one "copy" of Serializable base to be included in your class B.

    This change fixes the problem (demo).