为什么这两个涉及受保护派生类的C++示例的编译方式不同?

Why do these two C++ examples involving a protected derived class compile differently?

本文关键字:C++ 编译 方式不 派生 受保护 两个 为什么      更新时间:2023-10-16

根据我的理解,派生类能够将派生类指针转换为基类指针,即使存在受保护的继承。

为什么在 vs2017 下这段代码是错误的,生成编译器错误?

#include<iostream>
using namespace std;
class base {
public:
virtual void f() { cout << "base"; }
};
class deri : protected base {
public:
void f() override { cout << "derived"; }
void test(base* bp) { bp->f(); }  
};

int main()
{
deri d, d2;
d.test(&d);   //error,conversion to inaccessible base class "base" is not allowed
}

我像这样重写代码,它编译成功:

class deri : protected base {
public:
void f() override { cout << "derived"; }
void test(deri* dp) { base*bp=dp;bp->f(); }  
};

int main()
{
deri d, d2;
d.test(&d);   //it's Ok,and prints derived.
}

在我看来,这两个代码只是做同样的事情,将 deri 指针转换为 一个基本指针,我很舒服。谁能告诉我这两个代码之间的区别?

在我看来,这两个代码只是做同样的事情,将 deri 指针转换为基本指针

但他们不会在同一个地方这样做。在第一个版本中,它是必须进行转换的main范围。但是main不能为了进行转换而访问base,因为main完全超出了允许这种转换的deri范围。

这就是访问控制的意义所在,让一个类告诉它在哪个范围内可以访问其成员(或基)的名称。即使你的两段代码(假设我们忽略了一段甚至不编译的事实)会导致完全相同的事情发生,仍然有编译器必须遵守的封装规则。

因此,您可以公开该base,也可以使用受保护的可访问性的限制。顺便说一句,protected基地在野外很少见。我建议你考虑一下你是否需要它。

恕我直言,假设编译器授权从deri*转换为base*,新获得的指针在main范围内将毫无用处!! 为什么? 原因如下:

class deri: protected base语句意味着:

  1. base中的private成员无法在deri中访问
  2. baseprotected成员将在deriprotected
  3. basepublic成员将在deriprotected

因此,在main范围内,假定转换的指针将无法访问dbase部分,那么为什么要首先进行转换(这就是为什么编译器不接受这些转换的原因)

在第二个示例中,main范围内没有发生转换,并且在test成员函数的定义中可以进行转换。为什么?出于与以前相同的原因(转换后的变量bpderi范围内定义,因此可以访问dp所指向对象的publicprotectedbase部分成员