C++继承深度解析
2022/6/15 5:20:12
本文主要是介绍C++继承深度解析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
一.继承的概念
继承是C++中代码复用的重要手段。通过继承,可以获得父类的所有功能,并且可以在子类中重写已有功能,或者添加新功能。
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Memory 7 { 8 public: 9 Memory() 10 { 11 cout << "Memory()" << endl; 12 } 13 ~Memory() 14 { 15 cout << "~Memory()" << endl; 16 } 17 }; 18 19 class Disk 20 { 21 public: 22 Disk() 23 { 24 cout << "Disk()" << endl; 25 } 26 ~Disk() 27 { 28 cout << "~Disk()" << endl; 29 } 30 }; 31 32 class CPU 33 { 34 public: 35 CPU() 36 { 37 cout << "CPU()" << endl; 38 } 39 ~CPU() 40 { 41 cout << "~CPU()" << endl; 42 } 43 }; 44 45 class MainBoard 46 { 47 public: 48 MainBoard() 49 { 50 cout << "MainBoard()" << endl; 51 } 52 ~MainBoard() 53 { 54 cout << "~MainBoard()" << endl; 55 } 56 }; 57 58 class Computer 59 { 60 Memory mMem; 61 Disk mDisk; 62 CPU mCPU; 63 MainBoard mMainBoard; 64 public: 65 Computer() 66 { 67 cout << "Computer()" << endl; 68 } 69 void power() 70 { 71 cout << "power()" << endl; 72 } 73 void reset() 74 { 75 cout << "reset()" << endl; 76 } 77 ~Computer() 78 { 79 cout << "~Computer()" << endl; 80 } 81 }; 82 83 class HPBook : public Computer 84 { 85 string mOS; 86 public: 87 HPBook() 88 { 89 mOS = "Windows 8"; 90 } 91 void install(string os) 92 { 93 mOS = os; 94 } 95 void OS() 96 { 97 cout << mOS << endl; 98 } 99 }; 100 101 class MacBook : public Computer 102 { 103 public: 104 void OS() 105 { 106 cout << "Mac OS" << endl; 107 } 108 }; 109 110 int main() 111 { 112 HPBook hp; 113 114 hp.power(); //子类调用power() 115 hp.install("Ubuntu 16.04 LTS"); 116 hp.OS(); 117 118 cout << endl; 119 120 MacBook mac; 121 122 mac.OS(); 123 124 return 0; 125 }
结果:
1 //HPBook类实例化过程 2 Memory() //先父母的成员变量 3 Disk() 4 CPU() 5 MainBoard() 6 Computer() //父母的自身 7 power() 8 Ubuntu 16.04 LTS 9 //MacBook类实例化过程 10 Memory() 11 Disk() 12 CPU() 13 MainBoard() 14 Computer() 15 Mac OS 16 ~Computer() 17 ~MainBoard() 18 ~CPU() 19 ~Disk() 20 ~Memory() 21 ~Computer() 22 ~MainBoard() 23 ~CPU() 24 ~Disk() 25 ~Memory()
继承构造调用关系:先是调用父类的成员变量,然后再调用父类自身,再调用子类,析构的顺序则与构造的顺序相反。
二.继承中的访问级别
子类不能直接访问父类的私有成员private。
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent 7 { 8 private: 9 int mv; 10 public: 11 Parent() 12 { 13 mv = 100; 14 } 15 16 int value() 17 { 18 return mv; 19 } 20 }; 21 22 class Child : public Parent 23 { 24 public: 25 int addValue(int v) 26 { 27 mv = mv + v; // ???? 如何访问父类的非公有成员 28 } 29 }; 30 31 int main() 32 { 33 return 0; 34 }
结果:编译错误
protected修饰的成员可以被子类及外界直接访问。
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent 7 { 8 protected: 9 int mv; 10 public: 11 Parent() 12 { 13 mv = 100; 14 } 15 16 int value() 17 { 18 return mv; 19 } 20 }; 21 22 class Child : public Parent 23 { 24 public: 25 int addValue(int v) 26 { 27 mv = mv + v; 28 } 29 }; 30 31 int main() 32 { 33 Parent p; 34 35 cout << "p.mv = " << p.value() << endl; //100 36 37 Child c; 38 39 cout << "c.mv = " << c.value() << endl; //100 40 41 c.addValue(50); 42 43 cout << "c.mv = " << c.value() << endl; //150 44 45 return 0; 46 }
用public修饰的的父类可以被子类及外界访问。用protected修饰的父类可以被子类访问,不能被外界访问。用private修饰的父类只能被父类的成员函数访问。
三.继承中子类与父类的同名成员变量,成员函数
通过作用域分辨符(::)访问父类中的同名成员
1 Child c; 2 c.mi = 100; //子类中的mi 3 c.Parent::mi = 1000; //父类中的mi
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent 7 { 8 public: 9 int mi; 10 11 Parent() 12 { 13 cout << "Parent() : " << "&mi = " << &mi << endl; 14 } //确认成员变量地址,定位类Parent 15 }; 16 17 class Child : public Parent 18 { 19 public: 20 int mi; 21 22 Child() 23 { 24 cout << "Child() : " << "&mi = " << &mi << endl; 25 } //确认成员变量地址,定位类Child 26 }; 27 28 int main() 29 { 30 Child c; 31 32 c.mi = 100; 33 34 c.Parent::mi = 1000; //作用域分辨符,和命名空间有点像 35 36 cout << "&c.mi = " << &c.mi << endl; //查看是子类的 37 cout << "c.mi = " << c.mi << endl; 38 39 cout << "&c.Parent::mi = " << &c.Parent::mi << endl; //查看的是父类的 40 cout << "c.Parent::mi = " << c.Parent::mi << endl; 41 42 return 0; 43 }
结果:
1 Parent() : &mi = 0xbfb99188 2 Child() : &mi = 0xbfb918c 3 &c.mi = 0xbfb9918c //证明调用的子类mi 4 c.mi = 100 //打印子类中的mi 5 &c.Parent::mi = 0xbfb99188 //证明调用的子类继承自父类的mi 6 c.Parent::mi = 1000 //打印父类中的mi
当子类和父类有同名成员时,父类成员被子类覆盖,但是它依然存在子类中。
父类和子类之间的重载:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent 7 { 8 public: 9 int mi; 10 11 void add(int v) //重载关系 12 { 13 mi += v; 14 } 15 16 void add(int a, int b) //重载关系 17 { 18 mi += (a + b); 19 } 20 }; 21 22 class Child : public Parent 23 { 24 public: 25 int mi; 26 27 void add(int x, int y, int z) 28 { 29 mi += (x + y + z); 30 } 31 }; 32 33 int main() 34 { 35 Child c; 36 37 c.mi = 100; //访问子类的mi 38 39 c.Parent::mi = 1000; //访问子类继承父类的mi 40 41 cout << "c.mi = " << c.mi << endl; 42 43 cout << "c.Parent::mi = " << c.Parent::mi << endl; 44 45 c.Parent::add(1); //解决方案 46 c.Parent::add(2, 3); 47 c.add(4, 5, 6); 48 49 cout << "c.mi = " << c.mi << endl; 50 51 cout << "c.Parent::mi = " << c.Parent::mi << endl; 52 53 return 0; 54 }
结果:
1 c.mi = 100 2 c.Parent::mi = 1000 3 c.mi = 115 //调用子类add(4, 5, 6) 4 c.Parent::mi = 1006 //调用父类add(1)和add(2,3)
子类无法重载父类中的成员函数(作用域不同),使用作用域分辨符c.Parent::add访问父类中的同名函数。
子类和父类中的函数不能构成重载关系,子类可以定义父类中完全相同的成员函数。
四.多重继承可能产生冗余的成员
菱形继承:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class People 7 { 8 string m_name; 9 int m_age; 10 public: 11 People(string name, int age) 12 { 13 m_name = name; 14 m_age = age; 15 } 16 void print() 17 { 18 cout << "Name = " << m_name << ", " 19 << "Age = " << m_age << endl; 20 } 21 }; 22 23 class Teacher : public People 24 { 25 public: 26 Teacher(string name, int age) : People(name, age) //调用父类构造函数 27 { 28 } 29 }; 30 31 class Student : public People 32 { 33 public: 34 Student(string name, int age) : People(name, age) //调用父类构造函数 35 { 36 } 37 }; 38 39 class Doctor : public Teacher, public Student 40 { 41 public: 42 Doctor(string name, int age) : Teacher(name, age), Student(name, age) 43 { 44 } 45 }; 46 47 int main() 48 { 49 Doctor d("Delphi", 33); 50 51 d.print(); 52 53 return 0; 54 }
结果:编译出错
这篇关于C++继承深度解析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23增量更新怎么做?-icode9专业技术文章分享
- 2024-11-23压缩包加密方案有哪些?-icode9专业技术文章分享
- 2024-11-23用shell怎么写一个开机时自动同步远程仓库的代码?-icode9专业技术文章分享
- 2024-11-23webman可以同步自己的仓库吗?-icode9专业技术文章分享
- 2024-11-23在 Webman 中怎么判断是否有某命令进程正在运行?-icode9专业技术文章分享
- 2024-11-23如何重置new Swiper?-icode9专业技术文章分享
- 2024-11-23oss直传有什么好处?-icode9专业技术文章分享
- 2024-11-23如何将oss直传封装成一个组件在其他页面调用时都可以使用?-icode9专业技术文章分享
- 2024-11-23怎么使用laravel 11在代码里获取路由列表?-icode9专业技术文章分享
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享