通过using声明改变个别成员的可访问性
c++的语法中通过在派生类中使用using声明可以忽略继承方式 , 而让派生类对于基类的私有和保护成员具有特殊的访问权限 , 甚至可以改变派生类对象对于基类成员的访问权限 .
个人认为这种语法很容易让别人对于自己的代码产生误解 , 应该尽量少用或不用 . 为防止自己忘记 , 下面记录一下个人的理解 .
引用之c++ primer5 p546
通过在类的内部使用using声明语句 , 我们可以将该类的直接或间接基类中的任何可访问成员标记出来 (非私有成员) . using声明语句中名字的访问权限由该using声明语句之前的访问说明符来决定
白话文解释 : 在派生类的内部通过using声明语句 , 我们可以忽略继承方式 ,改变派生类中可访问的基类成员在派生类中的访问权限 .
通过using声明改变类的继承方式
文字可能不好理解 , 看代码实例更容易体会
1 class base 2 { 3 public: 4 int base_public; 5 protected: 6 int base_protect; 7 private: 8 int base_private; 9 }; 10 11 class derive :private base 12 { 13 public: 14 using base::base_public; 15 protected: 16 using base::base_protect; 17 private: 18 //using base::base_private; // error , 编译器报错 , 不可访问 19 };
代码示例中 , 派生类derive通过private的方式继承了基类base , 然而又通过using声明改变了基类成员的访问权限 ,
也就是说这段代码中 , 虽然表面上派生类是以private的方式继承了基类 ,而实际上派生类对于基类的访问权限就是public的方式 !
代码实例中可以看出在派生类中无法通过using声明来标记基类的私有成员 , 也验证了书中的话 .
由于继承的特性 , 基类的私有成员仍然会自动成为派生类的私有成员
然而这样的代码 , 很容易让人产生误解 .
通过using声明 , 做出一些不合常规的代码
using声明语句中名字的访问权限由该using声明语句之前的访问说明符来决定
通过这一特性 , 甚至可以改变基类成员在派生类中的访问权限 ! 同样通过一些代码来演示
1 #pragma warning (disable:4996) 2 #include <iostream> 3 4 class base 5 { 6 public: 7 int base_public = 1; 8 protected: 9 int base_protect = 2; 10 private: 11 int base_private = 3; 12 }; 13 14 class derive :private base 15 { 16 public: 17 //在public作用域声明基类中的成员 18 using base::base_public; 19 using base::base_protect; 20 //using base::base_private; // error , 编译器报错 , 不可访问 21 }; 22 23 int main() 24 { 25 derive test; 26 std::cout << "基类的公有成员: "<< test.base_public << std::endl; 27 std::cout << "基类的保护成员: " << test.base_protect << std::endl; 28 //std::cout << "基类的私有成员: " << test.base_private << std::endl; //error , 不可访问 29 30 system("pause"); 31 return exit_success; 32 }
代码中通过给基类的成员设定了默认初始值以便访问时显示 , 最终的运行结果如下
基类的公有成员: 1 基类的保护成员: 2 请按任意键继续. . .
代码中派生类继承时同样使用private的方式继承 , 然而我们把using声明放在了public权限下 , 由于 " using声明语句中名字的访问权限由该using声明语句之前的访问说明符来决定"
所以此时基类中的公有成员和保护成员都变成了派生类中的公有成员 , 也就是说通过using声明 , 我们通过私有继承的派生类 比 公有继承的访问权限反而更高 !
在main()函数中 派生类的对象可以访问基类的保护成员也验证了基类的保护成员在派生类中的访问权限已变成公有 .
也就是说通过这样的方式派生类对象可以访问基类的保护成员 , 而基类自己的对象却无法访问 .
需要注意的是通过派生类访问基类的保护成员时 , 编译器并不会给出智能提示 .
通过在类的内部使用using声明语句 , 我们可以将该类的直接或间接基类中的任何可访问成员标记出来 (只限于非私有成员) . using声明语句中名字的访问权限由该using声明语句之前的访问说明符来决定