派生类向基类转换的可访问性的个人理解
派生类向基类的转换是否可访问由使用该转换的代码决定 , 同时派生类的派生访问说明符也会有影响. 假定d继承自b:
1 只有当d公有继承b时 , 用户代码才能使用派生类向基类的转换;如果d继承b的方式是受到保护的或者是私有的 , 则用户代码不能使用该转换.
2 不论d以什么方式继承b , d的成员函数和友元都能使用派生类向基类的转换; 派生类向其直接基类的类型转换对于派生类的成员和友元来说永远是可访问的.
3 如果d继承b的方式是公有的或者受保护的 , 则d的派生类的成员和友元可以使用d向b的类型转换; 反之 , 如果d继承b的方式是私有的 , 则不能使用.
以上节选自c++ primer p544页
由于第一次读到的时候感觉非常的难以理解 , 因此记录下个人的理解 , 防止自己忘记 , 文中的代码编译环境为vs2017
第一条的个人理解 :
只有当d公有继承b时 , 用户代码才能使用派生类向基类的转换;如果d继承b的方式是受到保护的或者是私有的 , 则用户代码不能使用该转换.
个人理解: 当派生类以共有方式继承基类时 , 才可以使用基类指针指向派生类来操纵 . 而其他两种继承方式是失败的 . 所以一个结论即使是发生多态时 , 也必须是公有继承时 , 基类指针才可以指向派生类
代码示例 :
1 //只有公有继承时 , 基类指针或引用才可以指向派生类对象 , 再发生多态时 ,同样有效 2 #pragma warning (disable:4996) 3 #include <iostream> 4 5 class base 6 { 7 public: 8 virtual void mempublic() { std::cout << "base公有成员被调用" << std::endl; } 9 protected: 10 void memprotected() { std::cout << "base保护成员被调用" << std::endl; } 11 private: 12 void memprivate() { std::cout << "base私有成员被调用" << std::endl; } 13 }; 14 15 class derive :public base 16 { 17 public: 18 virtual void mempublic() override{ std::cout << "derive公有成员被调用" << std::endl; } 19 void mempri() 20 { 21 this->base::memprotected(); 22 this->mempublic(); 23 std::cout << "derive的个人函数" << std::endl; 24 } 25 }; 26 class derive_pro : protected base 27 { 28 public: 29 virtual void mempublic() override { std::cout << "derive_pro公有成员被调用" << std::endl; } 30 }; 31 class derive_pri : private base 32 { 33 public: 34 virtual void mempublic() override { std::cout << "derive_pri公有成员被调用" << std::endl; } 35 }; 36 37 int main() 38 { 39 std::cout << "--派生类--" << std::endl; 40 base * dev = new derive; 41 //base * dev2 = new derive_pro;//error 编译器报错, 不允许对不可访问的基类的转换 42 //base * dev3 = new derive_pri;//error 编译器报错, 不允许对不可访问的基类的转换 43 44 system("pause"); 45 return 0; 46 }
第二条的个人理解 :
在理解第二条前 , 首先应该明白一句话 , 同样节选自c++ primer5 p544页
派生访问说明符对于派生类的成员及友元能否访问其直接基类的成员没有什么影响 .对基类成员的访问权限只与基类中的访问说明符有关
这句话的含义 , 可以理解为不同的继承方式影响的是派生类的对象对于基类成员的的访问权限 , 而对于派生类内部 (派生类的成员函数中) 对基类成员的访问权限无关.
也就是说无论是公有继承还是私有继承 , 保护继承 , 在派生类的内部同样可以访问基类的公有成员和保护成员
那么接下来开始理解第二条
不论d以什么方式继承b , d的成员函数和友元都能使用派生类向基类的转换; 派生类向其直接基类的类型转换对于派生类的成员和友元来说永远是可访问的.
什么含义已经很显而易见了 , 无论派生类对于基类的继承方式是什么 , 派生类的成员和友元永远都有对于基类的的保护成员和公有成员的访问权限 , 这里需要注意的是派生类的成员和友元限于派生类内 , 而不是派生类的对象
代码示例 :
1 //代码中只对私有继承进行了展示 , 可以看出私有继承时 , 并不影响派生类中访问基类的共有成员和保护成员 2 class base 3 { 4 public: 5 int base_public; 6 protected: 7 int base_protect; 8 private: 9 int base_private; 10 }; 11 12 class derive :private base 13 { 14 public: 15 int dev1 = base_public; 16 int dev2 = base_protect; 17 //int dev3 = base_private; //error , 编译器警告成员不可访问 18 };
第三条 :
如果d继承b的方式是公有的或者受保护的 , 则d的派生类的成员和友元可以使用d向b的类型转换; 反之 , 如果d继承b的方式是私有的 , 则不能使用.
理解方式参考第二条 , 第三条并不是第二条的悖论 , 因为这句话有一个关键字 "d的派生类的成员" , 所以本意为
当派生类以公有和保护的方式继承基类时 , 则派生类的派生类的成员(就是类的内部)和友元才拥有可以访问基类的保护和公有成员的权限 , 而如果是私有的 , 这显然不可以 , 因为基类的所有成员已经变为派生类的私有成员 , 所以派生类的派生类并不能访问他们.