根据我的理解,派生类能够将派生类指针转换为基类指针,即使存在受保护的继承。
为什么在 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
语句意味着:
base
中的private
成员无法在deri
中访问base
protected
成员将在deri
protected
base
public
成员将在deri
protected
因此,在main
范围内,假定转换的指针将无法访问d
的base
部分,那么为什么要首先进行转换(这就是为什么编译器不接受这些转换的原因)
在第二个示例中,main
范围内没有发生转换,并且在test
成员函数的定义中可以进行转换。为什么?出于与以前相同的原因(转换后的变量bp
在deri
范围内定义,因此可以访问dp
所指向对象的public
和protected
base
部分成员