c++ - 在基类/派生类的成员函数/友元函数中Derive* to Base*转换

标签 c++ class inheritance derived-class

代码如下:

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;
}

这是关于 Derived-to-Base Conversion 的可访问性的 C++ primer:

• User code may use the derived-to-base conversion only if D inherits publicly from B. User code may not use the conversion if D inherits from B using either protected or private.

• Member functions and friends of D can use the conversion to B regardless of how D inherits from B. The derived-to-base conversion to a direct base class is always accessible to members and friends of a derived class.

• Member functions and friends of classes derived from D may use the derived-to- base conversion if D inherits from B using either public or protected. Such code may not use the conversion if D inherits privately from B.

但它并没有谈到B中从C/D到A的转换或A中从B/C/D到A的转换。我认为第一次转换会失败,第二次会成功。但结果(见代码中的注释)让我感到惊讶。

A 类是 B/C/D 类的基类,所以我认为 A 中发生的 Derive-to-Base 转换(in void A::ga(B*,C*,D*))会成功,但是编译器提示。从 C++ primer 引用的规则 2 我知道从 B 到 A in void B::gb(B*,C*,D*) 的转换会成功,但为什么从 C/D 转换到 A in void B::gb(B*,C*,D*) 也成功了吗? 为什么?

最佳答案

这就是无障碍的乐趣:

But it didn't talk about the conversion happen in B from C/D to A

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

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

理由就是标准:

  • (11.2/5) 如果基类是可访问的,则可以将指向派生类的指针隐式转换为指向该基类的指针
  • (11.2/1) 如果使用 protected 访问说明符将一个类声明为另一个类的基类,则基类的公共(public)成员和 protected 成员可作为派生类的 protected 成员进行访问。如果使用私有(private)访问说明符将一个类声明为另一个类的基类,则基类的公共(public)成员和 protected 成员可以作为派生类的私有(private)成员访问
  • (11.2/4) N 的基类 B 可在 R 访问,如果 (...) R 出现在类 N 的成员或友元中,并且 B 的虚构公共(public)成员将是私有(private)成员或 N 的 protected 成员。
  • (5.10/3) 进一步解释说,如果基数不可访问,则派生到基数的转换是非法的。

conversion happen in A from B/C/D to A ... I thought ... success.

A 不是 B 的后代。因此它无权访问其 protected 私有(private)成员/继承。

关于c++ - 在基类/派生类的成员函数/友元函数中Derive* to Base*转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28784738/

相关文章:

c++ - 在另一个类中使用对象的构造函数

java - 请求基类中的方法

c++ - 通过组合添加类功能

c++ - tinyxml2 : how to know number of characters read successfully from a stream buffer

c++ - 给定两个相距已知距离的相机的两个图像,如何测量到物体的距离

c# - 将没有根对象的json反序列化为c#/vb.net类

python - 在 python 2.5.1 或更早版本中使用属性和 setter

c++ - 将闭包作为“类方法指针”?

C++11 自动变量

c++ - 重写派生类中基类私有(private)成员的行为,C++