1

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?

user1086635
  • 1,536
  • 2
  • 15
  • 21

4 Answers4

1

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?

Community
  • 1
  • 1
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
1

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.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • The analogy with functions is not really good. In the case of member functions, `virtual` means that an unqualified function call will be dispatched to the final overrider, i.e. defines *which* of the functions will be called, but there may be many overriders. On the other end, with `virtual` inheritance, the keyword means that the base will be *unique*. – David Rodríguez - dribeas Jan 01 '12 at 16:22
  • @DavidRodríguez-dribeas: Fair point. Though virtual inheritance is more subtle yet, since you can mix virtual bases with non-virtual bases of the same type... ultimately, there's no way around understanding the whole thing, and no analogy can ever be a substitute. – Kerrek SB Jan 01 '12 at 16:36
  • @KerrekSB Non-virtual base classes are unmoved by the occurrence of virtual base classes of the same type in the same hierarchy, just like non-virtual functions are unmoved by the occurrence of virtual functions with the same name in the same hierarchy. The rules are not exactly similar (virtual base class matching is based on type (= qualified name), virtual function matching is based on unqualified name, a function can be implicitly virtual not a base class...) but the rules are somewhat similar. – curiousguy Aug 05 '12 at 05:52
1

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.

curiousguy
  • 8,038
  • 2
  • 40
  • 58
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • "_whenever a type D inherits virtually from a type B, the D subobject will contain a hidden pointer to the B subobject_" the Itanium C++ ABI does not have a hidden pointer! – curiousguy Aug 05 '12 at 05:42
0

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.