Lucas
Lucas

Reputation: 767

Implementation of pure virtual function via inheritance

I have the following situation:

class Fork {
    public:
        virtual void use() = 0;
};

class Spoon {
    public:
        virtual void use() = 0;
};

class SilverSpoon : public Spoon {
    public:
        virtual void use() { }
};

class SilverSpork : public SilverSpoon, public Fork {
    public:
        using SilverSpoon::use;
};

I was hoping that the pure virtual function Fork::use would be defined by SilverSpoon::use in SilverSpork. However, I get

error: cannot declare variable ‘spork’ to be of abstract type ‘SilverSpork’
note:  because the following virtual functions are pure within ‘SilverSpork’:
note:  virtual void Fork::use()

Is there a way to solve this without having to add

virtual void use() {
    SilverSpoon::use();
}

to SilverSpork?

Upvotes: 1

Views: 4010

Answers (3)

masoud
masoud

Reputation: 56529

Fork::use() and Spoon::use() are two different methods with same name which are extending to SilverSpork.

Compiler expects both of them to be implemented. It's just a name conflicting not overriding nor overloading. A possibility is inheriting Fork and Spoon from a base virtual class:

class Object {
    public:
        virtual void use() = 0;    
};

class Fork : virtual public Object {
};

class Spoon: virtual public Object {
};

class SilverSpoon : public Spoon {
    public:
        virtual void use() { cout << "SilverSpoon" << endl; }
};

class SilverSpork : public SilverSpoon, public Fork {
    public:
        using SilverSpoon::use;
};

Diagram:

                                    +---------------+
                                    |    Object     |
                                    +---------------+
                                      ^           ^
                                      |           |
                                      |           |
                                      |           |
                       +---------------+         +---------------+
                       |    Spoon      |         |     Fork      |
                       +---------------+         +---------------+
                               ^                  ^
                               |                  |
                               |                  |
                               |                  |
                       +---------------+          |
                       |  SilverSpoon  |          |
                       +---------------+          |
                                      ^           |
                                      |           |
                                      |           |
                                      |           |
                                   +---------------+
                                   |  SilverSpork  |
                                   +---------------+

Upvotes: 2

Mark B
Mark B

Reputation: 96301

Since you use multiple inheritance, you actually inherit two different abstract use methods and you have to override both of them in your child.

The first question you need to ask yourself is why a SilverSpork has the same use behavior as a SilverSpoon. If it really does, I can't believe I'm going to suggest this, but you could possibly solve this problem by using diamond inheritance with a new virtual base:

class Utinsil
{
    public:
        virtual void use() = 0;
};

class Fork : public virtual Utinsil {
};

class Spoon : public virtual Utinsil {
};

class SilverSpoon : public Spoon {
    public:
        virtual void use() { }
};

class SilverSpork : public SilverSpoon, public Fork {
};

int main()
{
    SilverSpork silver_spork;
}

Upvotes: 2

Pete Becker
Pete Becker

Reputation: 76458

There's no inherent connection between Fork and Spoon, and the fact that they both have a virtual function named use doesn't make one. However, if you add a new class, say, Utensil that defines a pure virtual function use(), and derive both Fork and Spoon from it as a virtual base, you've got a connection. With that, the class SilverSpork will pick up the implementation of SilverSpoon::use as the overrider for use in its direct base Fork. This is known as "dominance".

class Utensil {
public:
    virtual void use() = 0;
};

class Spoon : public virtual Utensil {
public:
    virtual void use() = 0; // or can omit this, relying on Utensil
};

class Fork : public virtual Utensil {
public:
    virtual void use() = 0; // or can omit this, relying on Utensil
};

class SilverSpoon : public Spoon {
public:
    void use() { }
};

class SilverSpork : public SilverSpoon, public Fork {
}; // OK: SilverSpoon::use overrides Fork::use

Upvotes: 4

Related Questions