Polymorphism vs regular inheritance? - c++

I use polymorphism so frequently, but it suddenly dawned upon me. I have the case where my code is:
class A{
class B : public A{
class C : public A{
and I use class A as a polymorphic parameter type for passing in B or C sub types:
//Accepts B and C objects
void aMethod(A* a){
However, I gave A a virtual destructor- this is the only reason A (and B and C) contain a vtable pointer.
So my question is, if I hadn't declared A with a virtual destructor, then A wouldn't be polymorphic- I wouldn't be able to pass objects of type B or C in aMethod()??
So is non-polymorphic inheritance just about sharing code, whereas polymorphism (the base class must have a vtable) allows passing sub types as arguments of the base class type?

In this code you provide,
void aMethod(A a){
the a formal argument is not polymorphic. It's passed by value. When you pass in a B or C object as actual argument, you're just slicing it down to an A, that is, you're copying the A base class sub-object only.
Regarding
” So is non-polymorphic inheritance just about sharing code, whereas polymorphism (the base class must have a vtable) allows passing sub types as arguments of the base class type?
it combines two questions that have to be treated separately.
Inheriting from a non-polymorphic class is about sharing of code, yes, but it also introduces an is-a relationship, which can be important for e.g. passing by reference.
Inheriting from a polymorphic class (one with one or more virtual member functions) allows you to override base class functionality, or to implement it where the base class leaves that as a derived class responsibility – typically by having pure virtual member functions. This means that member functions in the base class can call your derived class’ member functions. Also, that calling member functions via a base class pointer or reference, can call your derived class’s implementations.

Non-polymorphic types also contain a subobject for each base class, and upcasts are still implicit.
You can therefore pass objects of derived classes just fine even when there is no polymorphism. The receiver will act on the base subobject, just as happens for data members and non-virtual functions of polymorphic types.

A class with its destructor the only virtual method, like your class A, is an oddity. AFAIK, such a class has no necessity in well designed code.
From your question, it is not clear whether the virtual destructor is needed (i.e. if you ever call the destructor of classes B or C through a reference or pointer to class A), but if it is, your code smells. If it is not, then simply make the destructor non-virtual.

Related

Why is a virtual function in a derived class also virtual?

Is there a good reason why a virtual function is virtual by default in a derived class and it is not even possible to remove virtuality completely in the derived function?
The reason why I want this behaviour is the same reason I do not want every function to be virtual by default. The compiler might generate vtables which costs performance.
There should be a vtable for the base class (I want polymorphism there), but no vtable for the derived class (I do not want polymorphism there, why should I want that, only because it derives of a class with polymorphism?).
The problem I want to solve is to better understand virtual functions. I just do not get this design decision and wonder if there is any reason for this.
A vtable for a particular class has pointers to the virtual functions for that particular class. A vtable for a base class does not point to the virtual functions overridden by a derived class. There could be many derived classes, and the base class knows about precisely zero of them, so there's no way to have pointers to those functions. Only a derived class's vtable may have pointers to the derived class's functions.
The point of a virtual function is that, if you convert an object of the derived class to a base class pointer/reference, then calling any virtual function declared in the base class must call the most derived class's version of that function for that object. The only way to do that is if the vtable for that object has a pointer to the most-derived-class's version of that function. And that can only happen if the vtable for that object is the derived class's vtable.
That's how vtable's work.
If the derived class doesn't have a vtable of its own, which points to its own overridden member functions rather than the base class functions, then virtual dispatch can't work.
I do not want polymorphism there, why should I want that, only because it derives of a class with polymorphism?
But you do want polymorphism. You asked for it. If you inherit from a polymorphic base class and override one of its virtual functions, you are declaring the intent to use polymorphism. If you didn't want polymorphism, you wouldn't inherit from a polymorphic base class.
I think you are confused about what a vtable does. A vtable for a class C deriving from B basically maps functions specifiers to function pointers for class C. So if you do
B* ptr = new C;
ptr->foo();
we have to look up at runtime, which function to call. In the end, we need a function pointer to C::foo since B cannot possibly know where that lies, since it does not know about C at all. Hence, here we need C's vtable to make the call. Now you could argue that we do not need Bs vtable here. But ptr could also to an Object of type B, so there you need the B vtable.
Arguably, one could do something like this (of course, pseudo code):
virtual_call_to_foo(B* ptr) {
if(ptr->is_actually_base_class) {
ptr->B::foo(); // non-virtual call
} else {
ptr->vtable["foo"](); // indirect call
}
}
But that wouldn't be better than just also using a vtable for B since you already have the indirection there.
Further, note that a call through a pointer to C won't be virtual if C::foo is final:
B* ptr = new C;
ptr->foo(); // virtual call
static_cast<C*>(ptr)->foo(); // non-virtual call, the compiler can inline this
When a method is declared, the declaring class decides if it is virtual, according to the nature of what the method does.
When you override such a method, your overriding method is a specialized version of doing the exact same thing. Your overriding method cannot decide that it is doing something that cannot be specialized, the base class has already made that decision. The nature of the method is decided by the class that originally declared it, the base class.
Vtables are an implementation detail that should not affect any of this.

Meaning of 'virtual' in classes

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.

single virtual inheritance

I understand that virtual inheritance of a base class creates a common shared base class among multiple derived classes, thus addressing the DDD problem. If I have only one derived class for my base class, is there a difference when I inherit the base virtually or non-virtually ? Basically I am trying to understand explanation provided in the query Is it possible to forbid deriving from a class at compile time? where Usage_lock base class is inherited virtually to prevent derivations from the class Usable. If I remove this virtual key, the behaviour changes i.e. I am able to derive subclasses from Usable. So I want to understand difference cause by virtual key in single inheritance scenarios.
The primary difference in a single virtual inheritance case is that only the most-derived class calls the constructor of virtually inherited bases, and all of the other classes are provided a reference to the constructed class (this happens behind the scenes).
So, in the example, the since attempting to further derive Usable would require the new class to call the Usable_lock constructor (which is private), it is impossible for any other classes to be derived from Usable. Only Usable is allowed to construct the lock object, due to it being a friend of the lock.
Virtual Inheritance was basically introduced to solve the classical problem of Diamond shaped Inheritance.
Consider, the following classes:
class Base {};
class Derived1: Base {};
class Derived2: Base {};
struct MostDerived: Derived1, Derived2 {};
MostDerived class here has 2 instance of Base because of this diamond shaped hierarchy.
To solve this problem, C++ uses the virtual keyword and introduces the concept called Virtual Inheritance.
Thus adding the virtual keyword here, as:
class Derived1: virtual Base {};
class Derived2: virtual Base {};
Ensures that now there will only be one instance of Base inside MostDerived class.
And the MostDerived class instantiates this instance of Base class by calling its constructor.
With the above background(emphasized bold text), consider the following for the code example:
Usable class derives virtually from Usable_lock, so the derived class Usable MUST instantiate the Usable_lock base class of the object by calling its constructor.
But Usable_lock class has an private constructor so only the class itself can access the constructor, thus preventing other classes from deriving from it.
Reference from the C++03 Standard:
Section 12.6.2 Initializing bases and members
Paragraph 6:
All sub-objects representing virtual base classes are initialized by the constructor of the most derived class(1.8). If the constructor of the most derived class does not specify a mem-initializer for a virtual base class V, then V’s default constructor is called to initialize the virtual base class subobject. If V does not have an accessible default constructor, the initialization is ill-formed. A mem-initializer naming a virtual base class shall be ignored during execution of the constructor of any class that is not the most derived class.
A virtual base class will be constructed by the most derived class. By deriving virtually, and making the constructor of such base private, there is no way another class may construct it, hence effectively preventing derivation. However, its quite an artificial construct, and it comes with some overhead too.

Polymorphism c++

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.

virtual function - vtable

Let's say I have class A who inherits from class B and C (multiple inheritance).
How many vtable members class A would have ?
What's the case in single inheritance ?
In addition, suppose:
Class A : Public B {}
and:
B* test = new A();
Where does test gets its vtable from? What's assignment?
I assume it gets B's part of A's vtable, but does A's constructor changes its fathers (B) vtable too ?
First, vtable's are implementation specific. In fact, nowhere in the standard is specified that vtable's must exist at all.
Anyway, in most usual cases, you would get one vtable pointer per base class with virtual functions. And, as Yuval explained, nobody "fills" the vtable's when an object is constructed; you have one vtable per class with virtual functions, and objects just have pointers to their correct vtable (or vtable's, in case of multiple inheritance). In your single-inheritance example, test would have a pointer to A's vtable, assuming that A has at least one virtual function (inherited from B or newly declared in A).
Generally speaking - you need at least one vtable entry for each virtual function you inherit. If you have no virtual functions, you have no vtable.
Generally speaking, a subclass will have a vtable pointer to each of the multiple superclasses it inherits from (assuming, obviously, that each of those classes have at least one virtual function).
I'm not quite sure I understood your second question. When building an object, part of the construction process is setting the relevant vtable pointers, this is something that is done implicitly by the c++ compiler by static analysis of the inheritance hierarchy. None of the vtables change, they are merely pointed at.
When a class defines virtual functions, the compiler silently inserts a hidden vPtr data member for each supported interface.
The vPtr points to the correct vTable for the object.
The vTable contains a list of addresses which point to function implementations.
Here's an example of sorts.
class Foo: public Bar, public Baz
{
VTable* bar_vPtr;
VTable* baz_vPtr;
// Bar overrides/implementations
void barOverride();
// Baz overrides/implementations
void bazOverride();
};
VTable:
&barOverride() // address of implementation
VTable:
&bazOverride() // address of implementation
When an object is created, the memory is created for the data members and not the methods. The methods will be in a common location to be accessible by all the objects. This [ one per class ] applies to VTable as it merely consists of a function pointer for each virtual function in the class.
As mentioned by Steven, compiler adds a hidden pointer to the base class, which is set when a class instance is created such that it points to the virtual table for that class, This pointer is also inherited by derived classes.
When an object of the derived class is assigned to the base class pointer, the hidden pointer in the base class is replaced with the address of the derived class's vtable.