• 2.1 C++面向对象编程_访问控制和继承


    面向对象的编程有三大特点:

    1. 封装;
      1. 抽象出数据成员、成员函数;
      2. 访问控制;
    2. 继承;
    3. 多态;

    本节来学习继承。

    继承

    之前定义过一个Person类如下:

    1. class Person {
    2. private:
    3. static int cnt;
    4. char *name;
    5. int age;
    6. public:
    7. ...
    8. };

    如果现在要再定义一个Student类,Student也是Person,难道之前在Person类中定义过的成员在Student类中都要再定义一次吗?

    答:不需要,可以使用继承。Student类继承Person类,这样Student类就会有Person类的所有属性。

    Student类定义如下:

    1. class Student : public Person {
    2. };

    在Student类中,我们没有额外定义成员,在main函数中,测试一下Student类是否可以使用Person类的成员。

    测试结果如下:

    可以看到,Student类使用了Person类的成员,也就是说,Student类成功的继承了Person类的成员定义。

    继承的控制关系

    为了讲述继承的控制关系,我们重新创建了一个father_son.cpp。

    在father_son.cpp中,我们重新创建了一个Father类,然后创建了一个继承Father类的Son类,代码如下:

     

    然后写出main函数,先测试一下继承是否有问题。

    测试结果如下,可以看到,继承成功了。

    接下来需要测试一下继承的权限,主要有以下几点:

    1. Son不能直接拿Father的私房钱:派生类不能访问基类的私有成员;
    2. Son可以向Father要钱:通过protected/public的成员函数;
    3. 儿子总是比外人亲:派生类可以访问protected成员,其他代码不可以;

    依次测试。

    1、派生类不能访问基类的私有成员

    在派生类中直接操作基类的Private成员,代码如下:

    编译报错,money是Father类的私有成员,派生类Son无法直接访问。

     2、通过protected/public的成员函数

    派生类无法直接访问基类的私有成员,但是可以通过基类的protected/public成员函数间接访问基类的私有成员。

    测试结果如下:

    3、 派生类可以访问protected成员,其他代码不可以

    如果将get_money和set_money都定义为public类型,那么Father的钱就很难保护了,但是设置为Private类的话,Son又获取不了了。

    这时候,可以将它们设置为protected类型,这样派生类Son可以访问,但是其他代码就不可以了。

    这时候,在main函数中调用set_money和get_money就会报错。

     

    但是,在派生类Son中调用仍然是正常的。

    将main函数中set_money和get_money的调用删掉。

    在Son类中调用。

     

     编译代码就没有问题了,测试结果也符合预期。

    类的成员类型

    总结一下类的成员类型:

    1. private:外界不可见,不能直接访问;
    2. protected:外接不可见,不能直接访问;子类可以访问;
    3. public:外界可以直接访问;

    调整访问控制

    有时候,基类的成员类型并不满足派生类的需要,那么可能就需要修改基类的成员类型。

    在Father类中添加一个protected类型的成员room_key,此时在派生类son中可以自由使用room_key,但是在别的函数体中不能自由使用。

    那么,是否有办法让其他函数体也能自由使用呢?

    答:有,在Son类中将room_key成员变为public类型就可以了。

    代码如下,在public类型中使用using Father::room_key,此时再编译就没有报错了。

     

    既然可以将room_key设置为public,那么是否可以将room_key设置为private?

    调整代码如下:

     此时编译会报错,认为这是一个protected类型的变量。

    派生类可以调整基类protected类型变量的类型,但是不可以调整基类private类型变量的类型,因为基类protected类型的变量对派生类来说是可见的,但是private类型的变量则不可见。

    报错,因为不能调整基类private类型变量的类型。

    总结一下,就是派生类可以使用using调整它自己可见的基类成员的类型,但是对于它不可见的基类成员,是不能修改的

    继承的控制关系

    接下来看一下,派生类继承的控制关系。

    基类成员在派生类中的访问控制属性如下:

    基类成员在派生类中的访问控制属性
    继承类型\基类访问属性publicprotectedprivate
    publicpublicprotected隔离
    protectedprotectedprotected隔离
    privateprivateprivate隔离

    表格中,第一列是继承的类型,第一行是基类的访问属性。

    可以看到,public方式继承的话,是不会改变基类成员的控制属性的。而无论使用哪种继承方式,private类型的基类成员,都是处于隔离状态的。

    但是,无论使用哪种继承方式,在派生类内部使用父类时无差别;不同的继承方式,会影响的是这两个方面:

    1. 外部代码对派生类的使用;
    2. 派生类的子类;

    修改代码,分别使用三种类型继承。

    他们继承的基类Father类定义如下。

    测试

    修改代码,在main函数中创建三个对象,然后分别调用基类Father的public类型成员——it_skill函数。

    根据表格的描述,只有public方式继承的Son_pub可以在类外调用,其余的都会报错。

    编译结果如下,符合预期。

    但是如果不在main函数中调用,只在派生类内部调用,那么就不会有问题。

    修改代码,在main函数中调用Son的play_game函数,在play_game函数中,会调用基类的protected类型成员(派生类内部调用)。

    编译测试,没有问题,结果也符合预期。

     也就是说,无论使用哪种继承方式,在派生类内部使用父类时无差别。

    覆写

    在基类中有一个it_skill函数,如果在派生类中也有一个同名函数,那么会发生什么事情呢?

    在Son_pub中创建一个it_skill函数,然后在main函数调用it_skill函数。

     

    编译测试,可以看到调用的是派生类的it_skill函数,而不是父类的it_skill函数,也就是发生了覆写。

    如果派生类没有it_skill函数,才会调用基类的it_skill函数。

    派生类对象的空间分布

    假设有一个基类Person,一个派生类Student。

    那么,他们的成员的空间分布如下:

    基类Person类有三个成员,派生类Student除了有继承自基类的三个成员外,还有自己定义的grade。

    同时,在派生类中,还有一个和基类同名的函数printfInfo。

    基类的printfIndo函数如下:

    再写一个测试函数test_func,传入一个Person类的引用,函数中只是调用了一下对应的printfInfo函数。

    main函数如下。

    由于发生了覆写,所以s.printfInfo其实调用的是派生类自己的printfInfo函数而不是父类的。

    需要注意的是,test_func函数传入的是Person类的引用,如果传入的是Person类的派生类Student,那么是否可以正常运行?

    答:是可以的。根据前面的空间分布分析,Student类的分布,一部分是继承自基类,一部分则是来源于自己。

    当调用test_func(s)时,传入的部分是属于基类的那部分,所以在test_func函数中调用的printfInfo函数,是基类的printfInfo函数,而不是派生类覆写的printfInfo函数。

    只有通过s.printfInfo调用的,才是覆写的派生类自己的printfInfo函数。

    测试结果如下:

  • 相关阅读:
    如何保证接口的幂等性?
    PMP考试有哪些技巧?
    web server apache tomcat11-09-JNDI Datasource
    Java项目:SSM共享汽车租赁平台
    curl认证过期
    回调函数机制
    Servlet的生命周期
    数据结构与算法——19.红黑树
    【头歌-Python】8.5 中文词频统计(project) 1~5关
    一文2600字教你接口测试基本知识点(超全)
  • 原文地址:https://blog.csdn.net/qq_33141353/article/details/125840039