当前位置: 代码迷 >> 综合 >> 关于C++ primer 15.5节访问与继承控制的理解
  详细解决方案

关于C++ primer 15.5节访问与继承控制的理解

热度:40   发布时间:2023-11-24 16:12:30.0

关于C++ primer 15.5节访问与继承控制的理解

第一次阅读时,对P543第一节“受保护的成员”感到有点难以理解,后来发现是阅读过程中对第二条和第三条特性产生了歧义,最后浪费了蛮多时间。知乎上也有对这个问题的讨论链接,有一些回答也做出了解答可以作为参考,下面是我自己的理解。

一、受保护的成员

先来看看C++primer这一节的原文:

  • 和私有成员类似,受保护的成员对于类的用户来说是不可访问的。
  • 和公有成员类似,受保护的成员对于派生类的成员和友元来说是可访问的。
    此外,protected还有另外一条重要的性质。
  • 派生类的成员和友元只能通过派生类对象来访问基类的受保护成员。派生类对于一个基类对象中的受保护成员没有任何访问特权。

第一点性质很好理解,类的用户如何使用一个类呢?当然是实例化一个对象出来,然后调用对象的成员变量和成员函数。如果访问的成员是private或者protected的,那调用肯定是不能成功的。比如下列代码,A.a=12;这个步骤就会出错,因为成员变量a是protected成员变量,当然是不能访问的。

class Base {
    Base() {
    a=10;}protected: int a;
};int main() {
    Base A;A.a=12;return 0;
}

二、 2,3点特性产生的歧义

第一次读第2点和第3点特性的时候,马上就产生疑惑了.
第2点提到从基类继承而来的proteceted成员是可以被派生类的成员和友元访问的。但是第3点似乎又立刻限制了第2点。派生类的成员和友元只能通过“派生类对象”来访问基类的protected成员,首先是只能通过对象来访问,其次这个对象必须是派生类对象,然而在实际的代码中,派生类的成员和友元访问protected成员似乎并没有这么多限制。
可以看如下代码,派生类中的test()函数直接访问继承而来的protected成员变量a是没有问题的,并不需要通过“派生类对象”。这里为了方便理解并没有写出友元的情况,其实友元函数也是相同的:

class Base {
    Base() {
    a=10;}protected: int a;
};class Derived:public Base {
    void test() {
    a=11;}
};

那么是第3点出错了吗?我查阅英文版C++primer后发现也是相同的描述。

三、对第3点特性的解释

实际上第3点特性并没有错,是我的阅读理解出现了问题。第3点的意思是“派生类中的成员和友元如果通过对象来访问基类的受保护成员,那么这个对象必须是派生类对象,如果这个对象是基类对象,那么是不能直接访问的这个对象的受保护成员的。”
第3点中“只能”这个词是加在“派生类”上的,而不是加在“对象”上的,因此在第二部分的代码中,不通过对象来访问protected成员变量并没有问题。
还是看代码比较直观:

class Base {
    Base() {
    a=10;}protected: int a;
};class Derived:public Base {
    //可以通过编译void test1() {
    this->a=22;}//不可以通过编译Base b;void test2() {
    b.a=22;}
};

test1()通过派生类对象访问受保护成员可以通过编译,test2()通过基类对象访问就不行。至于为什么要做出第3点这样的规定,书上已经做出了详细的解释,这边就不赘述了。

四、总结

总结一下,这三点特性其实是根据范围划分出来的。第1点特性针对的是类外的情况,即用户通过对象使用类的情况;第2点针对的是类内的情况,成员函数可以直接访问protected成员,就像直接访问private成员一样;第3点同样是针对类内的情况,但更加特殊,是在类内通过对象来访问受保护成员。
在学习的过程中,有的时候真的不怕知识点有多难多复杂,因为越难,有疑问的人也越多,相应的解答也就越多,多花时间也就能理解了,最怕这种钻牛角尖的小错误,还是只有自己会犯的,苦思冥想半天才发现自己走进了误区,浪费了很多时间。想起了“法国就是培根”的梗,还有点相似,哈哈哈。

  相关解决方案