Reputation: 767
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
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
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
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