我们知道,在类内的access specifier public 、protected、private都只是为了限定用户程序对类内的访问权限,而在继承list中的access specifier则是影响使用该derived类的用户对该类内的访问权限。public继承延续base部分的access specifier;protected继承则是把base public部分变成了protected,其余不变;private继承则是把所有base部分变成private。具体可以看primer p612 613的例子(english version)。
对于判断derived-to-base conversion是否legal,最重要的是该derived指针或base指针是否可以访问到base类中的public成员。这个准则实际上是为了保证让转换后的base指针可以像其他普通base指针一样可以访问应该可以访问得到的成员。这个判断准测与primer p613下面提出的3点是相匹配的。stackoverflow上有对此的讨论,我们结合它上面的代码来验证这个判断准则。
注意看注释!注释!注释!重要的事情说三遍...
1 class B;
2 class C;
3 class D;
4 class A{
5 public:
6 virtual ~A(){}
7 friend void gg(D* d);
8 void ga(B *b,C* c,D* d); int mem;
9 };
10
11 class B:protected A{
12 public:
13 void gb(B *b,C* c,D* d);
14 };
15 class C:public B{};
16 class D:public C{};
17
18 void A::ga(B *b,C*c,D*d){
19 A *a1=b; // error: 'A' is an inaccessible base of 'B' 原因:在A类中B类指针b无法访问base A部分的成员,即这里的b->mem是非法的(B是protected继承A),所以也就不能转换。
20 A *a2=c; // error: 'A' is an inaccessible base of 'C' 原因同上,这里的c->mem也是非法的,因为mem在C类中是protected的。
21 A *a3=d; // error: 'A' is an inaccessible base of 'D' 原因同上。
22 }
23 void B::gb(B *b,C*c,D*d){
24 A *a1=b; // no problem here ,这里没问题是因为在类B中,b->mem是合法的。
25 A *a2=c; //why do classes derived from B can sucessfully convert to A here? 这里c->mem是非法的,只有在类C或friend of class c中c->mem才合法。
26 A *a3=d; //why do classes derived from B can sucessfully convert to A here? 原因同上
27 }
28 void gg(D* d){
29 A* a=d; // 这里也会报错,同上
30 }
31 int main(){
32 B b;
33 C c;
34 D d;
35 A a;
36 gg(&d); // error: 'A' is an inaccessible base of 'D'
37 a.ga(&b,&c,&d);
38 b.gb(&b,&c,&d);
39 A a1(d); //error here;Does it mean the implicit conversion in the user code is also user code?
40 A a4=d; //same as above
41 return 0;
42 }
但是,下面那个例子打破了这个准则,问题在http://stackoverflow.com/questions/30524479/what-is-the-rationale-for-allowing-this-derived-to-base-conversion-when-it-seem 上。 根据里面的解释,我认为准则应该再加上primer中p614最顶端的那个条件:
member functions and friends of classes derived from D may use the d-to-b conversion if D inherits from B using either public or protected. Such code may not use the conversion if D inherits privately from B.
这就可以很好地解释下面那段代码了。
1 class Base
2 {
3 public:
4 int mem;
5 };
6
7 class Derived : protected Base
8 {
9 static void f(Derived *d)
10 {
11 d->mem; // OK, in this context, a Derived IS-A Base
12 Base *b = d;
13 }
14 };
15
16 int main()
17 {
18 Derived d;
19 //d.mem; // Compilation error : in this context a Derived IS-NOT-A Base
20 //Base *b = &d; // Compilation error too : consistent with the intuitive rule
21 return 0;
22 }
23
24 class Derived_Derived : public Derived
25 {
26 static void f(Derived *d)
27 {
28 //d->mem; // Compilation error : in this context a Derived IS-NOT-A Base (as expected)
29 Base *b = d; // COMPILATION OK : which seems to violate the rule above
30 }
31 };
本文链接:如何判断derived-to-base conversion是否legal,转载请注明。