C++: I have a base class A with a pure virtual function f() and then two classes B and C inherit virtually from A, and a class D that inherits from both B and C (the typical diamond structure):
A f() = 0
v/ \v
B C
\ /
D
Where and when does f() = 0 need to be implemented in the following cases?
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?)
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
Neither B nor C have pure virtuals of their own (-> possible way to skip implementation in B and C and "pass it through" to D?)
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implement f()? In which cases, if any, is it not possible for D to implement f()?
Are there any other common suggestions for these kind of problems?
Thanks.
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?)
Yes D MUST implement ALL the inherited pure virtual functions.
Unless a class implements all the pure virtual functions of the classes it derives from the class itself actas as an Abstract class.
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
D will have to implement the pure virtual function it inherits through its Base classes in any hierarchy. If its immediate Base class does not define a Pure virtual function, then that class becomes an Abstract class too, and unless D implements the inherited pure virtual function, it will become Abstract too.
Neither B nor C have pure virtuals of their own (-> possible way to skip implmentation in B and C and "pass it through" to D?)
D will have to implement the the pure virtual functions it inherits through A->B & A-C.Note that in this case both B and C will be Abstract classes.
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implment f()? In which cases, if any, is it not possible for D to implement f()?
D needs to implement foo() in all the above 3 conditions, to be able to be instantiable(Non-Abstract).
Conclusion:
A class needs to implement ALL the pure virtual functions it inherits from ALL it's base classes, failing to do so will make the class an Abstract class.
Virtual attribute is inherited, If a Super class declares a function virtual then the overridden function in the derived class is virtual too and it passes down the virtual attribute to all classes deriving from it.
Avoid the Diamond of Death! Unless you really understand the subtleties involved with it. A lot of people try to use virtual Inheritance when it is not really the most apt way to achieve what their design wants to achieve. The use of Virtual Inheritance is indeed necessary in some scenarios, it is nevertheless an important construct provided by the language, but more often used in wrong ways. So it makes sense to revisit your design once to verify if you really need virtual Inheritance.
Following might be a good read:
Multiple Inheritance - Part I
Multiple Inheritance - Part II
Multiple Inheritance - Part III
Both B and C have also pure virtual functions (-> do abstract classes must implement inherited pure virtuals?
Yes. Any class that is inherited from abstract class must implement virtual functions to be able to instantiate. Or else they will also be abstract.
Only one of them (B XOR C) has a pure virtual function (-> does the other still must implement f()?)
Since C also derived from A, it should also implement f().
Neither B nor C have pure virtuals of their own (-> possible way to skip implmentation in B and C and "pass it through" to D?)
You can do that. But that prevents instantiation of B or C alone like -
A *obj = new B(); // Error
A *obj = new C(); // Error
In which of the three above cases does D need to implement f()? In which cases is it optionally for D to implment f()? In which cases, if any, is it not possible for D to implment f()?
f() can be implemented in D alone as long as you do want all of it's parent classes to be abstract.
The only requirement is that at the "leaf" level (the most derived one) everything has an implementation (and possibly one only, otherwise ambiguity can arise if -at the point you access the graph- there are more implementation at a same "distance".
So D must implement everything has not been implemented yet, or everything has been implemented more than once through different paths (to disambiguate).
If something -at D level- is still left unimplemented ... D cannot be instatiated, and the implementation is demanded to and E, derived from D.
- Diamonds are forever -
No, abstract classes (presumably B and C) don't need to implement inherited pure virtuals. A child class like D will need to do so to be instantiated though.
No, again B and C will inherit the pure virtual method and it need only be overridden to generate a final concrete class.
Yes, this would pass through implementation to D, in one of two ways. If B and C both inherit virtually, then D would implement it once. If they don't inherit virtually then D would need to override both the B and C versions of f to be concrete.
If D is abstract it never needs to implement f. Assuming you mean it to be concrete, in all three cases you'd need to override f in D. Only if both B and C override f would D not need to.
Take a long look at your design and remove the diamond inheritance. In most cases that's going to be your best bet to prevent all these sorts of issues.
Related
Suppose base class B has a nonvirtual public function f() , which is unfortunately overridden by derived class D.
Then there's a D object d passed to a B pointer pB.
Is there a way to prevent calling pB->f()?
If you can change B, you can either make f virtual, or make it forward to a virtual protected do_f, or various other things.
If you can't change B, you can't stop it's public method being called, and you can't somehow intercept a call to a non-virtual base class method.
Your question essentially asks, “How do I make a function virtual?” You don’t give a reason why you can’t just do that, but maybe you can’t change the declaration of B.
If B has at least one virtual function, you could use RTTI to check if *pB is really a D and cast it to D& if so. You cannot make existing code that takes a B* do so; if your daughter class breaks when you call it as a B, it breaks the contract of that interface.
Otherwise, it might be possible to determine that *pB is a D somehow by calling the B interface, but that would be some rigmarole specific to B and D.
Let's imagine the following situation: A is an abstract class defining a pure virtual function void f(); B is a class that implements a function void f(); C inherits from both A and B:
struct A
{
void virtual f() =0;
};
struct B
{
virtual void f() { }
};
struct C : public A, public B
{
};
The question could be: Is C an abstract class? The requirements deriving from A being abstract are that the subclass implements the virtual function void f(). C does not implement it directly, but inherits it from B.
I can already answer this question: Yes, C is an abstract class. If you try to instantiate an object of type C you'll get a compilation error. So the actual question is: Why is C an abstract class?
I suppose that the fact that A::f and B::f have the same name and signature is not enough to draw a correspondence between these functions so to say that B::f implements A::f. From a technical point of view I can see that these functions "reside" in different parts of the object of type C (though I'm not really sure that my understanding is complete). But from a conceptual point of view I could easily imagine a situation where a class C wants to be an implementation of the abstract class A and, in order to implement the pure virtual function f, it uses the implementation of one of its parent classes. The solution is probably to do:
struct C : public A, public B
{
virtual void f() { B::f(); }
};
, which worked in my experiment. But is this trick necessary?
EDIT:
Further question: Is the order in which C inherits from A and B relevant? Would it change something if I wrote the following?
struct C : public B, public A
{
};
The answer (again, I test my codes, then I try to ask non-trivial questions) is no, it does not change anything. But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f. Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
C also inherits from B doesn't make a bit of difference when it considers the functions inherited from A. So, when it compiler sees that C doesn't override pure virtual from A, it makes it an abstract class.
The requirements deriving from A being abstract are that the subclass implements the virtual function
Not quite. The requirement is that the subclass overrides the pure virtual function, with a non-pure function. A function in one base class doesn't override one in another base class; C itself must declare an override to be non-abstract.
But is this trick necessary?
Yes. You have to override the function in a class derived from A; in this case, that means C.
Is the order in which C inherits from A and B relevant?
No, the declaration order makes little difference. The override must be declared in a class derived from A.
But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f.
It would override both, regardless of the declaration order of the base classes.
Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
Both are still accessible (although the name will need to be qualified since an unqualified f is ambiguous). The pure function still needs to be overridden to make the derived class non-abstract.
Since the other answers haven't been updated for your new questions, here are the answers to them.
But in this case (correct me if I'm wrong), C::f, if implemented, would override B::f, not A::f.
You're half wrong. Both A::f and B::f are overridden by C::f regardless of the order of inheritance.
Since A::f would not be accessible using a C object does it make sense to request that it is implemented?
But A::f is accessible using a C object. Consider this, rather typical use of inheritance:
void call_f(A& a) {
a.f();
}
int main() {
C c;
call_f(c);
}
If C doesn't override A::f, then this couldn't possibly work. It makes sense that a concrete subclass of A must implement A::f.
Say I have 4 classes:
class I { public: virtual void X() = 0; };
class A : public virtual I { public: virtual void X() { } };
class B : public I { };
class C : public A, public B { };
I, B and C are abstract, where as A is not. If I simply add virtual to the inheritance of I for B, then A::X() resolves I::X() in C.
However, I cannot change the source of B.
My question: Can I get A::X() to resolve I::X for C without being able to change B? I have tried declaring A and B to be virtual to C to no avail. I am trying to have no redundant code (e.g. have C declare X() { A::X(); }). Any neat hacks?
Also - there are a few questions very much like this, but I couldn't find any talking about using virtual inheritance. Please point to me one if I missed it.
Your problem is with the vtables. In your current code, you have two of them - one in A's I and one in B's I. As long as only A virtually inherits I, you could just as well use regular inheritance and save the overhead. If both virtually inherited I you'd have only one instance of I in C, therefore only one vtable, and A::X could indeed cover the pure virual I::X.
Given you can't change B, the only place you can take care of both vtables is C. In my opinion, the way to go is what you mention - just have C::X forward the call to A::X. There's no code duplication there, and it makes C non-abstract:
class C : public A, public B {
public:
virtual void X() { A::X(); }
};
As for virtual inheritance, there definitively have been some here. But you're welcome to ask...
This is quite good: When virtual inheritance IS a good design?
The problem here is that in C you have two interfaces I. That is why A::x() satisfies
its interface I - but it cannot make not abstract interface I from class B.
For C the only way to have exactly one interface of I - is to change B to derive from I virtually - in this way both I interfaces from A and from B will be merged to one in C. You cannot change B - so the only way is to add this redundant code which you are trying to avoid. I mean define C::X().
The only way I can think of is to compose a B* (or smart variant) into C instead of inheriting from it, and forward the appropriate methods. You can't do it while maintaining the inheritance, because the compiler won't know which I's inheritance chain to follow.
In following case, virtual is used to solve the diamond problem to have sub-object of class A shared with B and C.
For example:
class A { };
class B : virtual public A { };
class C : virtual public A { };
class D : public B, public C { };
Does this type of inheritance will be resolved at compile-time or run-time? I mean, how different is the meaning of virtual when used on functions and classes? Is there a concept of dynamic binding when virtual is used to inherit from base class?
Inheritance doesn't have to be "resolved", as you put it, so the question isn't very clear.
The important difference is between ordinary inheritance and virtual inheritance. If you inherit ordinarily, i.e. B : A, C : A, then the class D : B, C has two subclasses of type A, namely D::B::A and D::C::A. On the other hand, if B and C inherit virtually from A, then the ultimate subclass composition will be deferred until you define the final type. That is, B : virtual A and C : virtual A themselves each have a virtual subclass A which would become real if you were to instantiate either B or C. On the other hand, if you derive from the classes further, then the most derived class will contain only one subclass of type A.
Perhaps you may like to consider the analogy with member functions. If each derived class adds a member function of the same name as a base function, you end up with several distinct functions. On the other hand, if the base function is virtual, then you only ever have one function, which is defined in the most derived class. You still have some sort of function in each intermediate class (assuming the function isn't pure-virtual), but only the final class defines the "active" definition.
Virtual inheritance has an effect on constructors, namely that the virtual-base constructor (i.e. A() in the example) is called directly by the most derived class, i.e. D, and not by B or C. If you will, this is because only D "knows" that it contains only one A-subclass, so it is directly "responsible" for it. B and C just hold a virtual placeholder that gives way to the ultimate, most derived class.
Accessing a member function through any base pointer/reference behaves just as expected and is resolved in the usual fashion (i.e. dynamically, in general), but that has nothing to do with virtual inheritance. The actual function lookup may be a bit more complicated as it may involve an extra level of indirection, but that doesn't change anything fundamental.
Virtual inheritance is resolved at runtime.
Virtual inheritance, just like virtual functions, means that each instance of the class has access to runtime data that describes where the virtual thing can be found.
It's described failry well at How C++ virtual inheritance is implemented in compilers?
Does this type of inheritance will be resolved at compile-time or run-time?
Inheritance defines the shape (memory footprint) of the types and it is resolved always at compile time. On the other hand, access to the members of the base type will be resolved at runtime, the reason being that intermediate types in the hierarchy cannot know where the base subobject will be laid in memory in the most derived type.
I mean, how different is the meaning of virtual when used on functions and classes?
Types and functions are different at all levels, so there is not much to say here. The only common thing is that there is a part of the work that cannot be fully resolved at compile time. In particular, the similarity is that code that uses a virtual function depends on a vptr (virtual table pointer) to find the proper vtable (virtual table) for the most derived type, and in a similar way, access to the base object requires the use of a pointer stored in each subobject of a type that derives virtually from the base.
You can read more (about a particular implementation, all this is not part of the standard) in the Itanium C++ ABI, and in particular in the Non-POD Class Types.
As a brief summary, whenever a type D inherits virtually from a type B, the D subobject will contain a hidden pointer to the B subobject. The need for that pointer arises from the fact that the relative position of the B subobject with respect to D can change with further inheritance.
It is my understanding that virtual classes resolves compile time ambiguity. For example assume that both B and C have a getSize method.
Without virtual, a call to D.getSize attempts to use the base class getSize method. Since both B and C each have a getSize method, the compiler is unable to properly resolve the ambiguity and the code will not compile.
With virtual, a call to D.getSize uses the decedent getSize method allowing the code to compile correctly.
In some books there is written that class that declares or inherits a virtual function is called a polymorphic class.
Class B doesn't have any virtual functions but passes more than one is-a test.
Class C has one virtual function but doesn't inherit.
class A {};
class B : public A {};
class C
{
public:
virtual void f () {}
};
is class B or C polymorphic ?
2003: 10.3/1 states, clearly:
A class that declares or inherits a virtual function is called a polymorphic class.
You actually said this yourself, word-for-word, so I don't really understand what the question is.
C (and its descendants, if you add any) is polymorphic; A and B are not.
Note that, in a wider OOP sense, you can always perform some "polymorphism" in that C++ always allows you to upcast; thus all objects that inherit can be treated as a different (but related) type.
However, the term "polymorphic" is defined slightly differently in C++, where it has more to do with whether you can downcast as well. If you don't want to be confusing like the C++ standard, you might call this "dynamic polymorphism".
Per the standard, "A class that declares or inherits a virtual function is called a polymorphic class."
Because neither A nor B declare or inherit a virtual function, they are not polymorphic.
C declares a virtual function, so it is polymorphic.
class C is polymorphic, meaning that using dynamic_cast or typeid on a C& will do a runtime type check, and calling member functions through a C& or C* will use virtual dispatch.
(Of course, the as-if rule allows the compiler to avoid the runtime dispatch under some condition when it knows the runtime type in advance, such as when you just created the object.)
As #Bill mentioned in a comment, that isn't just what some books say, it's the definition of polymorphic class, found in the C++ standard (section 10.3, [class.virtual]):
Virtual functions support dynamic binding and object-oriented programming. A class that declares or inherits a virtual function is called a polymorphic class.