在基/派生类的成员函数/友元函数中派生* 到 Base* 的转换



这是代码:

class B;
class C;
class D;
class A{
    public:
        virtual ~A(){}
        friend void gg(D* d);
        void ga(B *b,C* c,D* d);
    };
class B:protected A{
    public:
        void gb(B *b,C* c,D* d);
};
class C:public B{};
class D:public C{};
void A::ga(B *b,C*c,D*d){
    A *a1=b;  // error: 'A' is an inaccessible base of 'B'
    A *a2=c;  // error: 'A' is an inaccessible base of 'C'
    A *a3=d;  // error: 'A' is an inaccessible base of 'D'
}
void B::gb(B *b,C*c,D*d){
    A *a1=b;  // no problem here 
    A *a2=c;  //why do classes derived from B can sucessfully convert to A here?
    A *a3=d;  //why do classes derived from B can sucessfully convert to A here?
}
void gg(D* d){
    A* a=d;
}
int main(){
    B b;
    C c;
    D d;
    A a;
    gg(&d);  // error: 'A' is an inaccessible base of 'D'
    a.ga(&b,&c,&d);
    b.gb(&b,&c,&d);
    A a1(d); //error here;Does it mean the implicit conversion in the user code is also user code?
    A a4=d;  //same as above
    return 0;
}

以下是关于派生到基础转换的可访问性C++入门:

• 仅当 D 公开继承时,用户代码才能使用派生到基数的转换 如果 D 从 B 继承,则用户代码可能不会使用转换,使用任一 受保护或私有。

• 成员函数和 D 的朋友可以使用转换为 B,无论 D 如何继承自 B。派生到基到直接基类的转换是 派生类的成员和朋友始终可以访问。

• 成员函数和从 D 派生的类的友元可以使用派生到- 如果 D 使用公共或受保护从 B 继承,则进行基本转换。这样 如果 D 私下从 B 继承,则代码可能不会使用该转换。

但是它没有谈到在B中从C/D到A的转换或A从B/C/D到A的转换。但是结果(请参阅代码中的注释(让我感到惊讶。

类 A 是类 B/C/D 的基类,所以我认为派生到基本转换发生在 A 中(无效 A::ga(B*,C*,D*(((会成功,但编译器抱怨。从C++引物参考文献的规则 2 中我知道在无效 B::gb(B*,C*,D*( 中从 B 到 A 的转换会成功,但为什么在无效 B::gb(B*,C*,D*( 中从 C/D 转换为 A 也会成功?为什么?

这就是可访问性的乐趣:

但它没有谈论B从C/D到A的转换。

继承是protected的:这意味着 B 知道继承并且可以引用它的基类,并且从 B 派生的类也有这种访问权限。

如果 B 继承 A

作为private,情况会略有不同:在 B 中,所有转换仍然会成功(因为 B 可以访问私有 A 基(,但在派生类的函数中,所有这些转换都将失败,因为它们无法访问 B 的私人生活(和继承(。

理由是标准:

  • (11.2/5(如果基类是可访问的,则可以将指向派生类的指针隐式转换为指向该基类的指针
  • (11.2/1( 如果使用受保护的访问说明符将一个类声明为另一个类的基类,则可以访问基类的公共成员和受保护成员作为派生类的受保护成员。如果使用专用访问说明符将一个类声明为另一个类的基类,则可以将基类的公共成员和受保护成员作为派生类的私有成员进行访问
  • (11.2/4( N 的基类 B 可在 R 处访问,如果 (...(R 出现在 N 类的成员或朋友中,B 的发明公共成员将是 N 的私人或受保护成员。
  • (5.10/3(进一步解释说,如果无法访问基础,则将派生转换为基础是非法的。

在 A 中从 B/C/D 到 A 的转换发生...我以为。。。成功。

A 不是 B 的十进制。 因此,它无法访问其受保护和私有成员/继承。

这是关于C++编程语言中访问说明符的声明

基类

的访问说明符控制对基类成员的访问以及指针和引用从派生类类型到基类类型的转换。考虑从基类 B 派生的类 D:

• 如果 B 是私有基,则其公共和受保护成员只能由 D 的成员函数和好友使用。只有好友和 D 的成员才能将 D∗ 转换为 B∗。

• 如果 B 是受保护的基,则其公共成员和受保护成员只能由 D 的成员函数和友元以及派生自 D 的成员函数和类的友元使用。只有 D 的友元和成员

以及派生自 D 的类的友元和成员才能将 D∗ 转换为 B∗。

• 如果 B 是公共基,则其公共成员可以被任何功能使用。 此外,其受保护的成员可以由 D 的成员和朋友以及从 D 派生的类的成员和朋友使用。任何函数都可以将 D∗ 转换为 B∗。

发生派生到基转换

时,发生转换的代码必须具有通过继承层次结构从派生类到基类的所有可访问性。

给定 OP 中的示例:

... //other same as before
void A::ga(B *b,C*c,D*d){
    A *a1=b;  // error: 'A' is an inaccessible base of 'B'
    A *a2=c;  // error: 'A' is an inaccessible base of 'C'
    A *a3=d;  // error: 'A' is an inaccessible base of 'D'  <<-- I'll explain this conversion 
}
...//other same as before

转换D->A发生在 A 中,因此 A 必须具有转换D->C->B->A的可访问性,我们看到D->CC->B是公开的,但B->A受到保护,这意味着 D 可以转换为 B,但会在 B->A 处停止,A.To 在 A 中启用转换,我们必须通过受保护的规则将 A 类声明为 B 类或 C 类或 D 类中的好友。然后编译器不会再抱怨了。

现在,如果从 A 派生的 B 类和派生自 B 的 C 类都作为私有继承怎么办?

... // others same as before
class B:private A{ // inherited as private
    public:
        void gb(B *b,C* c,D* d);
};
class C:private B{};  // inherited as private 
class D:public C{};
void A::ga(B *b,C*c,D*d){
    A *a1=b; 
    A *a2=c;  
    A *a3=d;  //    <--------------------------- I'll explain this 
}
void B::gb(B *b,C*c,D*d){
    A *a1=b; 
    A *a2=c; 
    A *a3=d;  //   <============================ and this
}
...  // others same as before

在函数A::ga中,转换D->C工作,但在C->BB->A中失败,因此我们必须在类B和C中将类A声明为友元才能获得可访问性。

在函数B::gb中,转换D->CB->A(通过私有规则(工作,但C->B失败,因此我们必须将类 B 声明为 C 类中的友元,以实现 B 中的D->A转换。

最新更新