How the compilers implement the virtual i开发者_Python百科nheritance?
In the following code:
class A {
public:
A(int) {}
};
class B : public virtual A {
public:
B() : A(1) {}
};
class C : public B {
public:
C() : A(3), B() {}
};
Does a compiler generate two instance of B::ctor
function, one without A(1)
call, and one with it? So when B::constructor
is called from derived class's constructor the first instance is used, otherwise the second.
It's implementation-dependent. GCC (see this question), for example, will emit two constructors, one with a call to A(1)
, another one without.
B1()
B2() // no A
When B is constructed, the "full" version is called:
B1():
A(1)
B() body
When C is constructed, the base version is called instead:
C():
A(3)
B2()
B() body
C() body
In fact, two constructors will be emitted even if there is no virtual inheritance, and they will be identical.
The compiler does not create another constructor of B - but it ignores the A(1)
. Since A
is virtually inherited, it is constructed first, with its default constructor. And since it's already constructed when B()
is invoked, the A(1)
part is ignored.
Edit - I missed the A(3)
part in C
's constructor initialization list. When virtual inheritance is used, only the most derived class initializes the virtual base classes. So A
will be constructed with A(3)
and not its default constructor. The rest still stands - any initializations of A
by an intermediate class (here B
) are ignored.
Edit 2, trying to answer the actual question regarding the implementation of the above:
In Visual Studio (at least 2010), a flag is used instead of having two implementations of B()
. Since B
virtually inherits from A
, before it calls A
's constructor, the flag is checked. If the flag is not set, the call to A()
is skipped. Then, in every class deriving from B
, the flag is reset after it initializes A
. The same mechanism is used to prevent C
from initializing A
if it's part of some D
(if D
inherits from C
, D
will initialize A
).
I suggest you to read some papers. These two are really interesting, especially the first since it comes from C++'s father:
[1] Bjarne Stroustrup. Multiple Inheritance for C++. The C/C++ Users Journal, May 1999.
[2] J. Templ. A Systematic Approach to Multiple Inheritance Implementation. ACM SIGPLAN Notices, Volume 28, No. 4 April 1993.
I used them as main references while making a seminar (as a student) on multiple inheritance in my university.
The Itanium C++ ABI is a useful resource for all questions like "how could this be implemented by C++ compilers".
In particular 5.1.4 Other Special Functions and Entities list different special member functions for different purposes:
<ctor-dtor-name> ::= C1 # complete object constructor ::= C2 # base object constructor ::= C3 # complete object allocating constructor ::= D0 # deleting destructor ::= D1 # complete object destructor ::= D2 # base object destructor
The 1.1 Definitions section is useful (but not complete):
base object destructor of a class T
A function that runs the destructors for non-static data members of T and non-virtual direct base classes of T.
complete object destructor of a class T
A function that, in addition to the actions required of a base object destructor, runs the destructors for the virtual base classes of T.
deleting destructor of a class T
A function that, in addition to the actions required of a complete object destructor, calls the appropriate deallocation function (i.e,. operator delete) for T.
From these definitions, the purpose of the complete object constructor and of the base object constructor are obvious.
As mentioned before, it depends on the compiler implementation.
But, usually each time a programmer adds a new method, is stored in code, even if there is another method with the same id. elsewhere ("overriden" or "overloaded").
The code for each method is stored only once, so if a class inherits and uses the same method from a parent class, internally, its uses a pointer to the code, it doesn't duplicates the code.
If a parent class defines a virtual method, and if a child class overrides it, both methods are stored. Each class has something called "Virtual Method Table" where there is a table of pointers to each method.
Don't worry about performance, the compiler doesn't duplicate code for methods.
精彩评论