• C++学习笔记(十五)


    在完成对C语言的学习后,我最近开始了对C++和Java的学习,目前跟着视频学习了一些语法,也跟着敲了一些代码,有了一定的掌握程度。现在将跟着视频做的笔记进行整理。本篇博客是整理C++知识点的第十五篇博客。

    本篇博客介绍了C++的继承。

    本系列博客所有C++代码都在Visual Studio 2022环境下编译运行。程序为64位。

    目录

    继承

    继承的基本语法

    继承方式

    继承中的对象模型

    继承中的构造和析构顺序

    继承的同名成员处理

    多继承


    继承

    继承的基本语法

    有些时候,类之间具有一定的关系。一些类拥有其他类的共性,和自己的特性。

    可以利用继承,减少重复的代码。继承的语法是:

    class A: 继承方式 B

    继承方式分为public protectedprivate

    A类称为子类,或派生类。B类称为父类,或基类。

    子类的成员既有父类的成员,也有自己的成员。从父类继承的成员体现了共性,子类自己的成员体现了个性。

    1. #include
    2. using namespace std;
    3. class same {
    4. public:
    5. void show(void) {
    6. cout << "It is object oriented programming" << endl;
    7. }
    8. void test(void) {
    9. cout << "Study this is very hard" << endl;
    10. }
    11. void thing(void) {
    12. cout << "It has encapsulation,inheritance and polymorphism" << endl;
    13. }
    14. };
    15. class Java :public same
    16. {
    17. public:
    18. void inform(void) {
    19. cout << "This is Java" << endl;
    20. }
    21. };
    22. class CPP :public same
    23. {
    24. public:
    25. void inform(void) {
    26. cout << "This is C++" << endl;
    27. }
    28. };
    29. int main(void)
    30. {
    31. Java learnjava;
    32. learnjava.inform();
    33. learnjava.show();
    34. learnjava.test();
    35. learnjava.thing();
    36. CPP learncpp;
    37. learncpp.inform();
    38. learncpp.show();
    39. learncpp.test();
    40. learncpp.thing();
    41. return 0;
    42. }

    same类有三个成员函数,show成员函数输出It is object oriented programming,test成员函数输出Study this is very hard,thing成员函数输出It has encapsulation,inheritance and polymorphism。Java类以public权限继承了same类,该类自己的成员函数inform输出This is Java。CPP类以public权限继承了same类,该类自己的成员函数inform输出This is C++。

    main函数定义了Java类对象learnjava和C++类对象learncpp,分别调用其成员函数,可见子类可以有父类的成员。程序的输出是:

    This is Java
    It is object oriented programming
    Study this is very hard
    It has encapsulation,inheritance and polymorphism
    This is C++
    It is object oriented programming
    Study this is very hard
    It has encapsulation,inheritance and polymorphism

    继承方式

    如果类A以public的继承方式继承了类X,那么X的public权限成员在A中仍然为public,X的protected权限成员在A中仍然为protected,X的private权限成员在A中不可访问。

    如果类B以protected的继承方式继承了类X,那么X的public权限成员和protected权限成员在A中均为protected,X的private权限成员在A中不可访问。

    如果类C以private的继承方式继承了类X,那么X的public权限成员和protected权限成员在A中均为private,X的private权限在A中不可访问。

    1. #include
    2. using namespace std;
    3. class base {
    4. public:
    5. int A;
    6. protected:
    7. int B;
    8. private:
    9. int C;
    10. };
    11. class son1 :public base
    12. {
    13. public:
    14. void func(void) {
    15. A = 10;
    16. B = 10;
    17. }
    18. void show(void) {
    19. cout << "A = " << A << endl;
    20. cout << "B = " << B << endl;
    21. }
    22. };
    23. class son2 :protected base
    24. {
    25. public:
    26. void func(void) {
    27. A = 12;
    28. B = 12;
    29. }
    30. void show(void) {
    31. cout << "A = " << A << endl;
    32. cout << "B = " << B << endl;
    33. }
    34. };
    35. class son3 :private base
    36. {
    37. public:
    38. void func(void) {
    39. A = 11;
    40. B = 11;
    41. }
    42. void show(void) {
    43. cout << "A = " << A << endl;
    44. cout << "B = " << B << endl;
    45. }
    46. };
    47. int main(void)
    48. {
    49. son1 s1;
    50. s1.func();
    51. s1.A = 15;
    52. s1.show();
    53. son2 s2;
    54. s2.func();
    55. s2.show();
    56. son3 s3;
    57. s3.func();
    58. s3.show();
    59. return 0;
    60. }

    base类的成员变量A B C分别为public protected private。子类son1 son2 son3分别以public protected private的方式继承了base类,并且都有func成员函数进行赋值,show成员函数用于输出。main函数中创建了son1 son2 son3类的对象并调用func函数show函数。

    程序的输出是:

    A = 15
    B = 10
    A = 12
    B = 12
    A = 11
    B = 11

    继承中的对象模型

    父类的所有非静态成员属性都会被子类继承,即使子类无法访问,也是被继承了。

    1. #include
    2. using namespace std;
    3. class base {
    4. public:
    5. int A;
    6. protected:
    7. int B;
    8. private:
    9. int C;
    10. };
    11. class son :public base
    12. {
    13. public:
    14. int D;
    15. void func(void) {
    16. A = 5;
    17. B = 10;
    18. D = 0;
    19. }
    20. };
    21. int main(void)
    22. {
    23. son s;
    24. cout << sizeof(s) << endl;
    25. return 0;
    26. }


    base类有public权限的成员属性A,protected权限的成员属性B,private权限的成员属性C,共三个成员属性。类son以public继承了base,自身还有成员属性D和成员函数func。

    main函数创建了son类对象s,并输出其大小。程序的输出是:16

    即使son类不可访问C,但是依然继承了C。

    继承中的构造和析构顺序

    创建子类对象也会调用父类的构造函数。先构造父类再构造子类,析构相反。

    1. #include
    2. using namespace std;
    3. class father {
    4. public:
    5. father() {
    6. cout << "A" << endl;
    7. }
    8. ~father() {
    9. cout << "Z" << endl;
    10. }
    11. };
    12. class son :public father
    13. {
    14. public:
    15. son() {
    16. cout << "a" << endl;
    17. }
    18. ~son() {
    19. cout << "z" << endl;
    20. }
    21. };
    22. int main(void)
    23. {
    24. son s;
    25. return 0;
    26. }

    father类的构造函数输出A,析构函数输出Z。father类的子类son的构造函数输出a,析构函数输出z。main函数创建了一个son类的对象s。程序的输出是:

    A
    a
    z
    Z

    继承的同名成员处理

    当子类与父类的成员属性同名时,通过子类对象,访问子类的同名成员直接访问即可,访问父类的同名成员则需要加作用域。

    如果子类出现和父类同名的成员函数,则子类的成员函数隐藏父类的同名成员函数,访问父类的同名函数需要加作用域。

    1. #include
    2. using namespace std;
    3. class father {
    4. public:
    5. void func() {
    6. cout << "This is father's func" << endl;
    7. }
    8. void func(int num) {
    9. cout << "This is father's func" << endl;
    10. cout << "And there is a number = " << num << endl;
    11. }
    12. int number = 5;
    13. };
    14. class son :public father
    15. {
    16. public:
    17. int number = 10;
    18. void func() {
    19. cout << "This is son's func" << endl;
    20. }
    21. };
    22. int main(void)
    23. {
    24. son s;
    25. cout << "Son's number is " << s.number << endl;
    26. cout << "Father's number is " << s.father::number << endl;
    27. s.func();
    28. s.father::func();
    29. s.father::func(100);
    30. return 0;
    31. }

    father类有成员变量number,起始值为5,此外重载了两个func成员函数,一个没有参数,输出This is father's func,另一个接收一个int类型变量,并会输出其值。son类以public的权限继承了father类,内有成员变量number,起始值为10,还有成员函数func输出This is son's func。这样父类和子类出现了成员属性同名和成员变量同名。

    main函数创建了son类对象s,并访问其本身和父类的同名成员函数以及同名成员变量。

    程序的输出是:

    Son's number is 10
    Father's number is 5
    This is son's func
    This is father's func
    This is father's func
    And there is a number = 100

    如果继承时出现了同名静态成员,那么通过子类对象,依然是访问子类的直接访问,访问父类的需要加作用域。

    1. #include
    2. using namespace std;
    3. class father {
    4. public:
    5. static int number;
    6. static void func(void) {
    7. cout << "This is father's func" << endl;
    8. }
    9. };
    10. class son :public father
    11. {
    12. public:
    13. static int number;
    14. static void func(void) {
    15. cout << "This is son's func" << endl;
    16. }
    17. };
    18. int father::number = 10;
    19. int son::number = 15;
    20. int main(void)
    21. {
    22. cout << "son's number = " << son::number << endl;
    23. cout << "father's number = " << son::father::number << endl;
    24. son s;
    25. cout << "son's number = " << s.number << endl;
    26. cout << "father's number = " << s.father::number << endl;
    27. s.func();
    28. s.father::func();
    29. son::func();
    30. son::father::func();
    31. return 0;
    32. }

    父类father和子类son都有静态成员变量number(都类外赋值),和静态成员函数func(输出不同语句)。main函数通过子类类名和子类对象访问了同名静态成员。程序的输出是:

    son's number = 15
    father's number = 10
    son's number = 15
    father's number = 10
    This is son's func
    This is father's func
    This is son's func
    This is father's func

    多继承

    C++允许一个类继承多个类,语法是:

    class 子类:继承方式 父类1 继承方式 父类2...{...}

    多继承可能导致父类中出现同名成员,需要用作用域区分。实际开发不建议使用多继承。

    1. #include
    2. using namespace std;
    3. class father1
    4. {
    5. public:
    6. int A;
    7. int C;
    8. };
    9. class father2
    10. {
    11. public:
    12. int B;
    13. int C;
    14. };
    15. class son :public father1, public father2
    16. {
    17. public:
    18. int D;
    19. };
    20. int main(void)
    21. {
    22. son s;
    23. s.A = 10;
    24. s.B = 20;
    25. s.father1::C = 15;
    26. s.father2::C = 16;
    27. s.D = 12;
    28. cout << "A in father1 is " << s.A << endl;
    29. cout << "B in father2 is " << s.B << endl;
    30. cout << "C in father1 is " << s.father1::C << endl;
    31. cout << "C in father2 is " << s.father2::C << endl;
    32. cout << "D in son is " << s.D << endl;
    33. return 0;
    34. }

    类father1有成员变量A和C,类father2有成员变量B和C,类son同时继承father1和father2,自身还有成员变量D。main函数创建了son类对象s,并访问其成员。由于son的两个父类都有成员变量C,因此需要用作用域区分。程序的输出是:

    A in father1 is 10
    B in father2 is 20
    C in father1 is 15
    C in father2 is 16
    D in son is 12
     

    如果类B和类C都继承自类A,而类D同时继承类B和类C。那么A的成员变量在B和C中可能有两个值,导致与事实的冲突。

    virtual关键字表示虚继承,被虚继承的类是虚基类,这样数据只有一份。

    1. #include
    2. using namespace std;
    3. class first {
    4. public:
    5. int number;
    6. };
    7. class second1 : virtual public first {
    8. };
    9. class second2 :virtual public first {
    10. };
    11. class third : public second1, public second2 {
    12. };
    13. int main(void)
    14. {
    15. third three;
    16. three.second1::number = 20;
    17. cout << three.second1::number << endl;
    18. cout << three.number << endl;
    19. three.second2::number = 25;
    20. cout << three.second2::number << endl;
    21. cout << three.number << endl;
    22. return 0;
    23. }

    first类有成员变量number,second1和second2对first类进行虚继承,而third类同时继承second1和second2。

    main函数创建了third的类对象three,并通过两个不同父类作用域修改number为不同值,这时运行结果:

    20
    20
    25
    25
    虚继承保证了这种继承的在子类数据的唯一性。

  • 相关阅读:
    inotify递归监控 和 inotify的限制与警告
    android 默认开启谷歌定位精准度
    【人工智能】知识表示
    解决flutter不识别yaml里面配置的git项目
    Java中线程的六种状态
    【vue.js】vue中的Ajax——json-server
    [vue]多组件共享数据与vuex模块化
    函数相关概念
    【SA8295P 源码分析 (三)】112 - QNX AIS Camera 出图代码过程详解 之 VFEDriver 源码分析(本文未完,待更新...)
    关于python多线程的一些理解
  • 原文地址:https://blog.csdn.net/m0_71007572/article/details/126334998