When I try to compile the following code:
class A {
public:
A(int v) : virt(v) { }
int virt;
int getVirt(void) const { return virt; }
};
class B : private virtual A {
protected:
B(int v) : A(v) { }
using A::getVirt;
};
class C : public B, private virtual A {
protected:
C(int v) : A(v), B(v) { }
using A::getVirt;
};
class D : public C {
public:
D(void) : C(3) { }
using C::getVirt;
};
#include <iostream>
int main(int argc, char *argv[]) {
D d;
std::cout << "The number is: " << d.getVirt() << std::endl;
return 0;
}
I get an error about D not instantiating A; is that correct? If a virtual base is embedded in the hierarchy do all derived classes also need to derive from that base, virtually, so they can call the parametric constructor of the virtual base?
BTW, here are the errors produced by G++:
Main.cpp: In constructor ‘D::D()’:
Main.cpp:22:18: error: no matching function for call to ‘A::A()’
Main.cpp:22:18: note: candidates are:
Main.cpp:3:5: note: A::A(int)
Main.cpp:3:5: note: candidate expects 1 argument, 0 provided
Main.cpp:1:7: note: A::A(const A&)
Main.cpp:1:7: note: candidate expects 1 argument, 0 provided
Virtual base class in C++ Virtual base classes are used in virtual inheritance in a way of preventing multiple “instances” of a given class appearing in an inheritance hierarchy when using multiple inheritances. Need for Virtual Base Classes: Consider the situation where we have one class A .
A derived class can access all the non-private members of its base class. Thus base-class members that should not be accessible to the member functions of derived classes should be declared private in the base class. Constructors, destructors and copy constructors of the base class.
When employing multiple inheritance, virtual base classes are used to prevent several "instances" of a particular class from appearing in an inheritance hierarchy. Hence option (b) is the correct answer. A virtual base class is used to avoid multiple copies of base class in the derived class.
Virtual classes are primarily used during multiple inheritance. To avoid, multiple instances of the same class being taken to the same class which later causes ambiguity, virtual classes are used.
That has nothing to do with access control (at least not primarily). Rather, you have to understand how virtual bases work: The virtual base subobject is initialized by the most derived class. Since you don't mention A
in the constructor initializer list of D
, the default constructor is tried, but doesn't exist.
To fix this, initalize A
properly in D
:
D() : A(3), C(3) { }
When you say A(3)
, name lookup is performed according to 12.6.2/2:
In a mem-initializer-id an initial unqualified identifier is looked up in the scope of the constructor’s class and, if not found in that scope, it is looked up in the scope containing the constructor’s definition.
As Drew Dorman rightly points out, you can force a direct path to the virtual base class by calling it ::A
and thus obtaining the desired access.
As Kerrek SB mentions, you need to initialize A
in the constructor for D
.
However, you must also explicitly tell the compiler that you are not accessing A
from its (privately) derived context by using the scope operator.
class D : public C {
public:
D(void) : ::A(3), C(3) { }
// ^^ Access this constructor from a global context
using C::getVirt;
};
This also means that your constructor must be public, as is already the case with your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With