• C++继承


    目录

     1、继承

    1、基类的处理构造函数和析构函数之外,其他的全盘继承

    2、是否能被子类的成员函数访问

    3、是否能被外界访问 

    2、继承三步骤

    有继承和组合的构造顺序

    同名隐藏(成员属性)

    3、继承关系中拷贝构造函数的实现

     4、继承之下的赋值运算符重载

    面向对象的三大特征:封装,继承,多态

    封装:封装是把客观事物抽象成类,并且把自己的属性和方法让可信的类或对象操作,对不可性的隐藏。 

    继承:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

    多态:允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。这就意味着虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

     1、继承

    继承的基本形式: 

    1. class 子类 继承权限 基类
    2. {
    3. };

    若未写继承权限,则默认是私有继承(一般不写私有继承)

    1. class A
    2. {
    3. public:
    4. int m_i;
    5. void Print()
    6. {
    7. cout << "A::print" << endl;
    8. }
    9. protected:
    10. int m_j;
    11. private:
    12. int m_k;
    13. };
    14. class B :A//默认是私有的继承
    15. {
    16. };

    1、基类的处理构造函数和析构函数之外,其他的全盘继承

    我们知道构造函数和析构函数是跟对象的创建与消亡的善后工作相关。我们所创建派生类的对象,虽然和基类的对象有相同之处,但是仍然是不同的对象。所以,适用于基类的构造函数和析构函数不可能完全满足派生类对象的创建和消亡的善后工作。因此,构造函数和析构函数不被继承。

    如下所示:worker类是从Person继承而来,大小为8 。

    1. class Person
    2. {
    3. public:
    4. Person(int num = 1000) :m_num(num) {}
    5. void print()
    6. {
    7. cout << "count = " << m_count << endl;
    8. }
    9. protected:
    10. int m_num;
    11. static int m_count;
    12. };
    13. int Person::m_count;
    14. class Student :public Person
    15. {
    16. public:
    17. Student(int num, const char* job) :Person(num)
    18. {
    19. m_job = new char[strlen(job) + 1];
    20. strcpy_s(m_job, strlen(job) + 1, job);
    21. m_count++;
    22. }
    23. private:
    24. char* m_job;
    25. };
    26. class Teacher :public Person
    27. {
    28. public:
    29. Teacher(int num,const char*job):Person(num)
    30. {
    31. m_job = new char[strlen(job) + 1];
    32. strcpy_s(m_job, strlen(job) + 1, job);
    33. m_count++;
    34. }
    35. private:
    36. char* m_job;
    37. };
    38. class Worker :public Person
    39. {
    40. public:
    41. Worker(int num,const char*job) :Person(num)
    42. {
    43. m_job = new char[strlen(job) + 1];
    44. strcpy_s(m_job, strlen(job) + 1, job);
    45. m_count++;
    46. }
    47. private:
    48. char* m_job;
    49. };
    50. void main()
    51. {
    52. Student s(1001, "student");
    53. Teacher t(1002, "teacher");
    54. Worker w(1003, "worker");
    55. w.print();
    56. s.print();
    57. Worker w1(1006, "worker");
    58. s.print();
    59. cout << sizeof(Worker) << endl;//8
    60. }

    2、是否能被子类的成员函数访问

    基类的权限:publicprotectedprivate
    publicpubicprotected private
    protectedprotectedprotected private
    private不可访问不可访问不可访问
    1. class A
    2. {
    3. public:
    4. int m_i;
    5. void Print()
    6. {
    7. cout << "A::print" << endl;
    8. }
    9. protected:
    10. int m_j;
    11. private:
    12. int m_k;
    13. };
    14. class B :public A//全部继承A
    15. {
    16. public:
    17. void set()
    18. {
    19. m_i = 20;
    20. m_j = 30;
    21. //m_k = 40;//私有的能被继承,不能被访问
    22. }
    23. };
    24. class C :protected A
    25. {
    26. public:
    27. void test()
    28. {
    29. m_i = 14;
    30. m_j = 13;
    31. //m_k = 12;//私有的能被继承,不能被访问
    32. }
    33. };
    34. class D :private A
    35. {
    36. public:
    37. void test()
    38. {
    39. m_i = 10;
    40. m_j = 12;
    41. //m_k = 14;//私有的能被继承,不能被访问
    42. }
    43. }
    44. class DD :public D
    45. {
    46. public:
    47. void ff()
    48. {
    49. //A的public和protected属性被D私有化
    50. m_i = 1;
    51. m_j = 2;
    52. m_k = 3;//
    53. }
    54. };

    3、是否能被外界访问 

    外界无法访问protected和private成员

    1. class A
    2. {
    3. public:
    4. int m_i;
    5. void Print()
    6. {
    7. cout << "A::print" << endl;
    8. }
    9. protected:
    10. int m_j;
    11. private:
    12. int m_k;
    13. };
    14. class B :public A//全部继承A
    15. {
    16. public:
    17. void set()
    18. {
    19. m_i = 20;
    20. m_j = 30;
    21. //m_k = 40;//私有的能被继承,不能被访问
    22. }
    23. };
    24. class C :protected A
    25. {
    26. public:
    27. void test()
    28. {
    29. m_i = 14;
    30. m_j = 13;
    31. //m_k = 12;//私有的能被继承,不能被访问
    32. }
    33. };
    34. void main()
    35. {
    36. cout << sizeof(B) << endl;
    37. B b;
    38. b.Print();
    39. b.m_i = 12;
    40. //b.m_j = 8;
    41. //b.m_k = 13;//外界不能使用
    42. C c;
    43. //C将属性m_i变成protected
    44. c.m_i = 12;
    45. c.m_j = 13;
    46. c.m_k = 14;//被C保护继承
    47. }

    2、继承三步骤

    1、除构造析构全盘接收

    2、改写

    3、添加子类特有的 

    1. class A
    2. {
    3. public:
    4. A() { cout << "A" << endl; }
    5. void print() { cout << "A::print" << endl; }
    6. ~A() { cout << "~A" << endl; }
    7. private:
    8. int m_i;
    9. };
    10. class B :public A
    11. {
    12. public:
    13. B() { cout << "B" << endl; }
    14. ~B() { cout << "~B" << endl; }
    15. private:
    16. int m_j;
    17. };
    18. void main()
    19. {
    20. B b;//A b
    21. }

    先调用基类A的构造函数,将所派生下来的数据成员先行构造,再调用B的构造函数;先析构B,再析构A。

    有继承和组合的构造顺序

    1、先按照继承顺序调用基类的构造

    2、按照组合顺序调用组合的构造

    3、调用自己的构造

    1. class CPU
    2. {
    3. public:
    4. CPU() { cout << "CPU" << endl; }
    5. };
    6. class KB
    7. {
    8. public:
    9. KB() { cout << "KB" << endl; }
    10. };
    11. class Mouse
    12. {
    13. public:
    14. Mouse() { cout << "Mouse" << endl; }
    15. };
    16. class Computer
    17. {
    18. public:
    19. Computer() { cout << "Computer" << endl; }
    20. private:
    21. CPU cpu;
    22. KB kb;
    23. Mouse ms;
    24. };
    25. class Touch
    26. {
    27. public:
    28. Touch() { cout << "Touch" << endl; }
    29. };
    30. class Laptop :public Computer
    31. {
    32. public:
    33. Laptop() { cout << "Laptop" << endl; }
    34. private:
    35. Touch tc;
    36. };
    37. void main()
    38. {
    39. Laptop lt;
    40. }

    同名隐藏(成员属性)

    派生类的成员函数和基类的函数同名同参,则将基类的函数隐藏

    1. class A
    2. {
    3. public:
    4. void print() { cout << "A::print" << endl; }
    5. protected:
    6. int m_i;
    7. };
    8. class B :public A
    9. {
    10. public:
    11. //print将派生下来的A的print隐藏了
    12. void print()
    13. {
    14. cout << "B::print" << endl;
    15. cout << m_i << " " << A::m_i << endl;
    16. }
    17. void set() { m_i = 10; A::m_i = 20; }
    18. protected:
    19. int m_i;
    20. };
    21. void main()
    22. {
    23. A a;
    24. B b;
    25. a.print();
    26. b.set();
    27. b.A::print();//利用b调用A的成员函数
    28. b.print();
    29. cout << sizeof(B) << endl;
    30. }

    3、继承关系中拷贝构造函数的实现

    1. class Person
    2. {
    3. public:
    4. Person(int num,const char *name ,char sex):m_num(num), m_sex(sex)
    5. {
    6. int len = strlen(name) + 1;
    7. m_name = new char[len];
    8. strcpy_s(m_name, len, name);
    9. }
    10. Person(Person& p) :m_num(p.m_num), m_sex(p.m_sex)//拷贝构造
    11. {
    12. m_name = new char[strlen(p.m_name) + 1];
    13. strcpy_s(m_name, strlen(p.m_name)+1, p.m_name);
    14. }
    15. ~Person()
    16. {
    17. delete[]m_name;
    18. m_name = NULL;
    19. }
    20. void Show()
    21. {
    22. cout << m_num << m_name << m_sex << endl;
    23. }
    24. private:
    25. int m_num;
    26. char* m_name;
    27. char m_sex;
    28. };
    29. class Student :public Person
    30. {
    31. public:
    32. Student(int num, const char* name, char sex,float score):Person(num,name,sex),m_score(score)
    33. {
    34. }
    35. ~Student()
    36. {
    37. }
    38. Student(Student& s) :Person(s)//拷贝构造
    39. {
    40. m_score = s.m_score;
    41. }
    42. void print()
    43. {
    44. Show();
    45. cout << m_score << endl;
    46. }
    47. private:
    48. float m_score;
    49. };
    50. void main()
    51. {
    52. Student s1(1001, "tianpangpang", 'f', 89);
    53. s1.print();
    54. Student s2(s1);
    55. s2.print();
    56. }

     4、继承之下的赋值运算符重载

    1、程序设计者在基类和派生类中都没有重载operator=函数; C++编译器将在基类和派生类中自动产生按位赋值的,重载operator=函数;C++编译器会在派生类的重载赋值函数中,加入基类重载赋值函数的调用,是C++编译器合成的代码;(完成行为的统一);

    2、程序设计者在基类中定义重载赋值函数;而在派生类中没有定义重载赋值函数;C++编译器将会在派生类中自动产生按位赋值的重载赋值函数。并合成代码,调用(关联)基类的重载赋值函数。

    3、程序设计者在基类和派生类中都定义了重载赋值函数;程序设计者在派生类中,没有指定调用基类的重载赋值函数时。C++编译器不会合成调用基类的重载赋值函数的代码。要在派生类的重载赋值函数调用基类的重载赋值函数,程序设计者必须自己加入调用代码。 

    4、程序设计者在基类中没有定义重载赋值函数(C++编译器将自动产生按位赋值的重载赋值函数)。而在派生类中定义了重载赋值函数。程序设计者在派生类中,没有指定调用基类的重载赋值函数。C++编译 器不会合成调用基类的重载赋值函数的代码。

    实现拷贝构造和赋值重载: 

    1. class Person
    2. {
    3. public:
    4. Person():m_sex('f'),m_age(20)
    5. {
    6. m_name = new char[1];
    7. *m_name = '\0';
    8. cout << "Person()" << endl;
    9. }
    10. Person(const char* name, char sex, int age):m_sex(sex),m_age(age)
    11. {
    12. m_name = new char[strlen(name) + 1];
    13. strcpy_s(m_name, strlen(name) + 1, name);
    14. }
    15. Person(Person& p) :m_sex(p.m_sex), m_age(p.m_age)
    16. {
    17. m_name = new char[strlen(p.m_name) + 1];
    18. strcpy_s(m_name, strlen(p.m_name) + 1, p.m_name);
    19. }
    20. Person& operator=(Person& p)
    21. {
    22. if (this == &p)
    23. return *this;
    24. delete[]m_name;
    25. m_name = new char[strlen(p.m_name) + 1];
    26. strcpy_s(m_name, strlen(p.m_name) + 1, p.m_name);
    27. m_sex = p.m_sex;
    28. m_age = p.m_age;
    29. return *this;
    30. }
    31. void print()
    32. {
    33. cout << m_name << " " << m_sex << " " << m_age << " ";
    34. }
    35. ~Person()
    36. {
    37. if (m_name != NULL)
    38. {
    39. delete[]m_name;
    40. m_name = NULL;
    41. }
    42. }
    43. private:
    44. char* m_name;
    45. char m_sex;
    46. int m_age;
    47. };
    48. class Student :public Person
    49. {
    50. public:
    51. Student():m_num(0),m_score(0) { cout << "Student()" << endl; }
    52. Student(int num, const char* name, char sex, int age, int score):m_num(num),Person(name,sex,age),m_score(score) {}
    53. void print()
    54. {
    55. cout << m_num << " ";
    56. Person::print();
    57. cout << m_score << endl;
    58. }
    59. Student(Student& s) :Person(s), m_num(s.m_num), m_score(s.m_score) {}
    60. Student& operator=(Student& s)
    61. {
    62. if (this == &s)
    63. return *this;
    64. Person::operator=(s);
    65. m_num = s.m_num;
    66. m_score = s.m_score;
    67. return *this;
    68. }
    69. private:
    70. int m_num;
    71. int m_score;
    72. };
    73. void main()
    74. {
    75. Student s;
    76. Student s1(1001, "zhangsan", 'f', 20, 78);
    77. s.print();
    78. s1.print();
    79. Student s2(s1);
    80. s2.print();
    81. s = s1;
    82. s.print();
    83. }
  • 相关阅读:
    Html 标题标签h1-h6详解和细节分析
    接口测试 —— requests 的基本了解
    Spark(OOM问题,数据倾斜问题)
    这4个网站太厉害了, 每一个都能帮你打开新世界大门
    [附源码]计算机毕业设计旅游网的设计与实现Springboot程序
    工厂方法模式
    supervisorctl(-jar)启动配置设置NACOS不同命名空间
    《Java并发编程实战》第2章-线程安全性
    软件测试的基础知识
    排序进阶----快速排序
  • 原文地址:https://blog.csdn.net/weixin_59179454/article/details/127873041