First off I apologize if there is another post out there that answers this, all the similar posts I found dealt with diamond inheritance schemes or defined functions, which this does not.
In short, I'm wondering if it is possible to have one class inherit from two other classes where both child classes has a function with the same name and arguments but it is defined in one child class, and pure-virtual in another. Furthermore if I can do this, would invoking the function on the pure-virtual/abstract class end up calling the defined function on the other child class with minimal changes to the derived class?
Example:
class A
{
public:
virtual void Set(int X) = 0;
};
class B
{
public:
virtual void Set(int X);
};
class AB : public A, public B
{
//other methods not relevant to example go here
};
int main(int argc, char **argv)
{
int Y = 5;
A* ObjectA = new AB();
ObjectA->Set(Y);
return 0;
}
So far my attempts to compile this basic example have been met with errors that say:
'AB' : cannot instantiate abstract class
due to following members:
'void A::Set(int)' : is abstract
When doing my own research I couldn't find a clear answer, but based on other questions that dealt with related topics I found that using a "using B::Set" in class AB may help with this. But when I try adding it to the AB class definition, the error persists.
Is there any way I can make this work?
If you had 2 normal functions Set in A and B, then using B::Set would tell the compiler that if you have object of class AB and call method Set of that object, B::Set will be invoked, if AB::Set not defined explicitly.
Your situation is different. You have pure virtual function A::Set that leads A to be abstract class. As AB does not override A::Set, AB becomes abstract too, that is why you cannot instantiate it.
What you can do here
You can implement AB::set to call B::Set:
class AB : public A, public B
{
public:
void Set(int x) { return B::Set(x); }
};
Also I do not recommend same method names for base classes, as I do not recommend multiple inheritance, try use aggregation instead.
Have you tried implementing the method:
class AB : public A, public B
{
void Set(int X) {}
};
The reason it's not working is that A::Set() is pure virtual. I.e. it has no implementation. But you try to call it. You have to override it in the derived class in order to be able to instantiate the derived class.
The using doesn't work in your case because you have an A*, so there's no ambiguity for the compiler.
In case you had:
AB* ObjectA = new AB();
ObjectA->Set(Y);
you'd have to use using inside the declaration of AB to resolve the ambiguity.
Class AB derives from A, A has a pure virtual method making the class abstract, AB must implement any pure virtual methods declared in a base class in order to be instantiated.
I would try to avoid multiple inheritance it can cause many headaches and there are generally better ways to solve a problem, for instance in this example I don't understand the point in deriving from both A and B, if B shares and in fact implements the same interface as A then surely B should be derived from A.
Related
Ok, this might be silly question but I can't figure out how to fix my problem.
Let's assume we have 4 classes
class A is a Base class
class B is derived from A with new methods (no override)
class C is derived from A
class D is derived from B (and also from A for inheritance)
my question is: how do I use a method defined in B in D?
If D inherit from B I get "error: member 'xxx' found in multiple base classes of different types"
if D does not inherit from B I get "use of undeclared identifier"
Here's how it's done - based on your description:
class A {
protected:
void foo();
};
class B : public A {
protected:
void bar();
};
class D : public B {
protected:
void baz() { B::bar(); }
};
Note that you should not have D inherit from A directly, except in very specific and rare cases. Inheritance is transitive.
Also, next time, Please post a Minimal, Complete, and Verifiable example and don't make us guess what you mean exactly.
In those cases in which the same method is available from the same subclasses from multiple inheritance paths are the "Diamond Pattern", and you can read about it here.
We have:
class A {
public:
int f();
int f(int);
//...
};
class B {
public:
int f();
int f(int);
//...
};
class AB : public A, public B {
public:
long f(double, double);
//...
};
A::f(), A::f(int), B::f(), B::f(int) are now hidden in class AB, and I want to use only A::f() and B::f(int) as if they weren't hidden:
AB ab;
ab.f(); // ab.A::f()
ab.f(1); // ab.B::f(1)
Is there a simpler way to achieve this than by writing the following code?
class AB : public A, public B {
public:
//...
int f() {return A::f();}
int f(int x) {return B::f(x);}
};
I thought of the using keyword but it doesn't distinguish between methods with the same name and different signatures.
The only way is to declare them and call the base class function that you want as you wrote.
You might have thought about using in some weird way "using" ex: using A::f; but you inherit all function signatures with the same and you cannot specify a single one.
The thing in AB class declaration is:
With just the inheritance
You got the interface and implementation from both base class you will have a error when calling to a method that is common on both of them(Note!Even if the signature is not the same).
theABVar.A::f(); will give you:
Error:"request for member 'f' is ambiguous"
But you can solve this with theABVar.A::f();(isn't this cool? :D)
When you add a method with the same name that in both base classes
The members in the base classes got hidden, therefore, a call to the method is not ambiguous any more.But to call method on base class you should do the same trick than before.
theABVar.f(); will give you
Ettor: no matching function for call to 'AB::f()'
When you try to use "using" for base class functions
You will get on compilation time, even if you don't use the function:
using A::f;
using B::f;
using declaration 'using B::f' conflicts with a previous using declaration
Any way, think twice about what you are doing. You want a function, that depending on the number/type of arguments it calls to a member of a different base class?. I can not imagine a lot of situations where that makes sense.
--------------Conclusion---------------
Think twice about what you are doing. Hiding methods is not usually good.
In your first example Clients can use explicit calls(they will be able to access all public members) theABVar.A::f(), theABVar.A::f(3), theABVar.B::f(), theABVar.B::f(3), theABVar.AB::f(3.0,3.0) and theABVar.f(3.0,3.0) .
You can create the functions you need as you specified(there is no simpler thing), but remember that clients can still call you base functions!
I made a test code as following:
#include <iostream>
using namespace std;
#ifndef interface
#define interface struct
#endif
interface Base
{
virtual void funcBase() = 0;
};
interface Derived1 : public Base
{
virtual void funcDerived1() = 0;
};
interface Derived2 : public Base
{
virtual void funcDerived2() = 0;
};
interface DDerived : public Derived1, public Derived2
{
virtual void funcDDerived() = 0;
};
class Implementation : public DDerived
{
public:
void funcBase() { cout << "base" << endl; }
void funcDerived1() { cout << "derived1" << endl; }
void funcDerived2() { cout << "derived2" << endl; }
void funcDDerived() { cout << "dderived" << endl; }
};
int main()
{
DDerived *pObject = new Implementation;
pObject->funcBase();
return 0;
}
The reason I wrote this code is to test if the function funcBase() can be called in an instance of DDerived or not. My C++ complier (Visual Studio 2010) gave me a compile error message when I tried to compile this code. In my opinion, there is no problem in this code because it is certain that the function funcBase() will be implemented (thus overriden) in some derived class of the interface DDerived, because it is pure virtual. In other words, any pointer variable of type Implementation * should be associated with an instance of a class deriving Implentation and overriding the function funcBase().
My question is, why the compiler give me such an error message? Why the C++ syntax is defined like that; i.e., to treat this case as an error? How can I make the code runs? I want to allow multiple inheritance of interfaces. Of course, if I use "virtual public" or re-declare the function funcBase() in Implementation like
interface DDerived : public Derived1, public Derived2
{
virtual void funcBase() = 0;
virtual void funcDDerived() = 0;
};
then everything runs with no problem.
But I don't want to do that and looking for more convenient method, because virtual inheritance may degrade the performance, and re-declaration is so tedious to do if inheritance relations of classes are very complex. Is there any methods to enable multiple inheritance of interfaces in C++ other than using virtual inheritance?
As you've defined it, your object structure looks like this:
The important point here is that each instance of Implementation contains two entirely separate instances of Base. You're providing an override of Base::funcBase, but it doesn't know whether you're trying to override funcBase for the Base you inherited through Derived1, or the Base you inherited through Derived2.
Yes, the clean way to deal with this is virtual inheritance. This will change your structure so there's only one instance of Base:
This is almost undoubtedly what you really want. Yes, it got a reputation for performance problems in the days of primitive compilers and 25 MHz 486's and such. With a modern compiler and processor, you're unlikely to encounter a problem.
Another possibility would be some sort of template-based alternative, but that tends to pervade the rest of your code -- i.e., instead of passing a Base *, you write a template that will work with anything that provides functions A, B, and C, then pass (the equivalent of) Implementation as a template parameter.
The C++ language is designed in such a way that in your first approach without virtual inheritance there will be two parent copies of the method and it can't figure out which one to call.
Virtual inheritance is the C++ solution to inheriting the same function from multiple bases, so I would suggest just using that approach.
Alternately have you considered just not inheriting the same function from multiple bases? Do you really have a derived class that you need to be able to treat as Derived1 or Derived2 OR Base depending on the context?
In this case elaborating on a concrete problem rather than a contrived example may help provide a better design.
DDerived *pObject = new Implementation;
pObject->funcBase();
This creates a pointer of type DDerived to a Implementation. When you are using DDerived you really just have a pointer to an interface.
DDerived does not know about the implementation of funcBase because of the ambiguity of having funcBase being defined in both Derived1 and Derived2.
This has created a inheritance diamond which is what is really causing the problem.
http://en.wikipedia.org/wiki/Diamond_problem
I also had to check on the interface "keyword" you have in there
it's an ms-specific extension that's recognised by visual studio
I think C++ Standard 10.1.4 - 10.1.5 can help you to understand the problem in your code.
class L { public: int next; /∗ ... ∗/ };
class A : public L { /∗...∗/ };
class B : public L { /∗...∗/ };
class C : public A, public B { void f(); /∗ ... ∗/ };
10.1.4 A base class specifier that does not contain the keyword virtual,
specifies a non-virtual base class. A base class specifier that
contains the keyword virtual, specifies a virtual base class. For each
distinct occurrence of a non-virtual base class in the class lattice
of the most derived class, the most derived object (1.8) shall contain
a corresponding distinct base class subobject of that type. For each
distinct base class that is specified virtual, the most derived object
shall contain a single base class subobject of that type. [ Example:
for an object of class type C, each distinct occurrence of a
(non-virtual) base class L in the class lattice of C corresponds
one-to-one with a distinct L subobject within the object of type C.
Given the class C defined above, an object of class C will have two
subobjects of class L as shown below.
10.1.5 In such lattices, explicit qualification can be used to specify which
subobject is meant. The body of function C::f could refer to the
member next of each L subobject: void C::f() { A::next = B::next; } //
well-formed. Without the A:: or B:: qualifiers, the definition of C::f
above would be ill-formed because of ambiguity
So just add qualifiers when calling pObject->funcBase() or solve ambiguity in another way.
pObject->Derived1::funcBase();
Updated: Also very helpful reading will be 10.3 Virtual Functions of Standard.
Have a nice weekend :)
I have the following code:
#include <iostream>
class Grandma
{
public:
virtual void foo() = 0;
};
class Mom : public Grandma{};
class Dad
{
public:
void foo() { std::cout << "dad's foo impl"; }
};
class Me : public Mom, public Dad{};
int main()
{
Me m;
m.foo();
}
and getting : cannot instantiate abstract class
I know what this error means, I know I can't instantiate Grandma because of pure-virtual.
But why can't I instantiate Me, when compiler knows I am derived from Mom and Dad and Dad has foo implemented?
I know I can fixed it by adding foo into Me and inside it call e.g. Dad::foo, but I am afraid it is not solution for my case.
Is it really necessary to have virtual method implementation between its declaration and instantiated object (when traversing "class hierarchy graph")? See ASCI graph
A
|
B1 B2
\ |
C1 C2
| /
|/
D
|
E
When I want to instantiate E and have virtual declaration in A, the only way to make it run is to define it in A, B2, C1, D or E?
and similarly when is virtual declaration in C2 only way is to define it in C2, D or E?
I know this may be silly question, but I had a loooong day and can not think anymore.
Please, do not answer just with - "It is not possible", but try to add explanation why not.
Thank you!
EDIT -- foo() in Dad is of course should not be private
There is no relation between Dad class and Grandma class. Dad and Grandma are two completely different classes. Given that the method in Dad is not considered as an implementation of the pure virtual method in Grandma and has to be implemented in the Me class.
When you derive from an Abstract class(class containing atleast one pure virtual function) the deriving class needs to override and implement ALL the pure virtual member functions of the Base Class. If not, the deriving class becomes Abstract too, same applies to the classes deriving from the derived class further down the hierarchy.
Unfortunately you're right that you have to implement the virtual method in the path between original declaration and final instantiated object. Objects multiply inherited in can't implement that interface.
So from the question it sounds like you're trying to implement a parent interface in a child class by inheriting from the implementor. Instead of that approach, did you consider instead having the parent class delegate the work to a strategy pattern and then select the proper strategy in your child class. Then you can still compose implementations together and don't have to worry about the many complexities of multiple inheritance.
You are correct that a virtual function is only overridden by implementations provided by classes inheriting (potentially through several layers) from the class where the virtual function is originally declared.
However, depending on what you are actually trying to accomplish, Sister Class Delegation may what you want. Basically, you can declare virtual functions in a base common to both Grandma and Dad ('Person'?) and Grandma can call those functions even if only Dad provides an implementation when you're using a Me object. Even though Grandma would know nothing about Dad, when you use virtual inheritance any subclasses your final class pulls in can be used to satisfy virtual functions from the virtual base class.
Let's say we have
class A {
public:
virtual int foo() { cout << "foo!"; }
}
class B : public A {
public:
virtual int foo() =0;
}
class C : public B {
public:
virtual int foo() { cout << "moo!"; }
}
Is this really overriding? I think this is actually overloading.
What is the meaning of making something like this, design-wise?
We got a base class A. Then we got an abstract derived class B which is derived from the concrete class A, and then a realization of B via C.
What are we doing here and does it make any sense?
Overloading would mean that you had two functions of the same name but with different parameters. That's not the case here.
Example:
int functionA() { /*...*/ };
int functionA(int someParameter) { /*...*/ };
Overriding means rewriting a function with the same parameters in a subclass. That is what you presented as an example.
That's the definition part. Now on to the design:
When you have a pure virtual function, concrete subclasses have to override it. So by adding a pure virtual function, you ensure that all subclasses provide the same set of functions (=interface). This seems to be the case in the sample code.
But it is not a very good example, as the concrete superclass already implements a default functionality for foo(). When there is an abstract subclass that redefines it to be purely virtual, it is a sign for me that the class hierarchy is flawed because a subclass (and the callers of foo()) usually should be able to fall back to the default implementation. It's a bit hard to explain with such an abstract example, but a hierarchy like this is a bit suspicious to my eye.
It seems to me that the only effect of the pure virtual method here is to make B an abstract class.
It's still overriding, because when you have a pointer p of type A* to instance of class C, p->foo() still calls C::foo()
Probably, the designer wanted to insert an abstract class in the hierarchy deriving from some concrete class, and force overriding of the method in subclasses. I don't think it's terribly wise.
You're saying that classes deriving from B must implement int foo();. You might want to do something like this to force other programmers to think about how they want foo() to behave, but I think it's a bad idea - in reality they're likely to implement by calling A::foo().
If you just want to make B abstract, give it a pure virtual destructor - you'll also need to provide an implementation of the destructor to avoid link error though.