Re: Virtual inheritance and typedef
"David Vandevoorde" <daveed.vandevoorde@gmail.com> wrote:
Virtual inheritance ensures that there is only one base class
DefaultPolicies (in the original example; see also Figure 16.1 in
the book). When you write Policies::P3 in the BreadSlicer template,
a lookup is performed and finds two types P3: The one in Policy3_is
(found once) and the one in DefaultPolicies (found three times, via
Discriminator<..., 2>, Discriminator<..., 3>, and Discriminator
<..., 4>). However, DefaultPolicies is always a base class of
Policy3_is, so the "domination rule" applies and the type from the
more derived class is selected (i.e., Policy3_is).
Now, if ordinary inheritance is used instead, we find the same
types again, but this time the DefaultPolicies in which we find P3
(three times) are NOT base classes of Policy3_is. So the dominance
rule does not apply and the compiler cannot choose between the two
P3 types.
I think I get it now:
---BEGIN CODE---
#include <iostream>
struct A
{
typedef int T;
};
struct B1 : /*virtual*/ A
{
typedef double T;
};
struct B2 : /*virtual*/ A
{
};
struct C : B1, B2
{
};
int main()
{
C::T x = 42;
std::cout << "x = " << x << std::endl;
return 0;
}
---END CODE---
Output on g++-4:
(1) With B1 and B2 both inheriting virtually from A, the program
compiles OK and prints: x = 42
(2) With either occurrence of 'virtual' (or both) commented out, the
following compiler error is generated:
main.cpp: In function 'int main()':
main.cpp:23: error: reference to 'T' is ambiguous
main.cpp: 5: error: candidates are: typedef int A::T
main.cpp:10: error: typedef double B1::T
[etc.]
(This time the g++ error is actually helpful!)
As I now understand it...
Lookup of C::T in main() finds both B1::T and A::T (the latter via
B2). With non-virtual inheritance, B1::T hides its own inherited
A::T, but cannot hide B2's inherited A::T, so both B1::T and A::T are
visible and C::T is therefore ambiguous.
But if both B1 and B2 inherit A virtually, the domination rule
applies and the most-derived declaration (in this case, B1::T) hides
all the others, even where these others are reachable "along a path
through the sub-object lattice that does not pass through the hiding
declaration." (to quote the C++98 Standard, Section 10.2/6)
Is this explanation correct?
I had noted that the _C++ Templates_ book refers to this Section of
the Standard in relation to the domination rule (footnote 2 on page
289), but, having never seen the Standard, I didn't realise that this
"domination rule" refers to virtual inheritance.
Since my original post I have discovered a draft version (2 Dec 1996)
of (most of) the C++98 Standard on Bjarne Stroustrup's web site:
ftp://ftp.research.att.com/pub/c++std/WP/CD2. But without Daveed's
explanation I doubt that I would ever have fathomed what Section
10.2/6 is getting at. (Stroustrup also has a draft C++0x Standard at:
http://www.research.att.com/~bs/SC22-N-4411.pdf. The domination rule
is now a Note in Section 10.2/10-11.)
Thanks to Daveed Vandevoorde and Joe Smith for your help.
P.S.
The _C++ Templates_ footnote referenced above (p. 289) also mentions
that there is a discussion of this issue in Section 10.1.1 of the
ARM. As I don't have access to a copy of this book, I will be
grateful if anyone who does can provide a short summary of the ARM's
rationale for the dominance rule.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]