在c++中通过类定义对象,而类与类之间也有着复杂的关系,所以题外话,我能理解到c++的编写者可能就想通过计算机语言去模拟世界万物之间的关系,这篇帖子主要从横向和纵向去讨论类之间关系
而在一个类中想要使用另一个类中的内容,无非三种方式,1.直接传参 2.传地址 3.在一个类中去定义另一个类
从横向来看,可以分为1.依赖 2.关联 3.聚合 4.复合,接下来用UML类图展示一下这几种横向关系
第一种,依赖,一个对象的一个功能需要依赖另一个对象存在,被依赖的对象作为工具使用, 在上图的例子中,CComputer 这个类对于CPerson来说,是作为Coding的一个工具,CComputer不是CPerson的一个特性,所以是依赖关系
第二种,关联,就类似于朋友之间的平等关系,关联的特点是随时建立,随时解除,利用指针去指向CFriend的地址
第三种,聚合,相当于强版本的关联,但聚合的目的是为了统一进行管理同类型的对象,就像是一个家庭,或者是一个班级,所以一般这里的对象都需要new出来的, 在聚合的析构里可以统一删除,统一创建
第四种,复合,又叫组合,是属于CPerson的一部分,类似于脑袋,双手
之所以建立这种类之间的关系,也是根据c++的单一性这个特点,每一个部分都是一个独立的个体,一个类的修改不会影响到其他的部分,也可以进行任意组合,下面是针对这个类图的代码
1 #include <iostream> 2 #include <time.h> 3 using namespace std; 4 5 6 class CHead 7 { 8 public: 9 void Say() 10 { 11 cout << "张个大嘴,哇啦哇啦" << endl; 12 } 13 }; 14 15 class CHand 16 { 17 public: 18 void Move() 19 { 20 cout << "比比划划" << endl; 21 } 22 }; 23 24 class CComputer 25 { 26 public: 27 void Coding() 28 { 29 cout << "C++ Coding....." << endl; 30 } 31 }; 32 33 class CFriend 34 { 35 public: 36 int rp; 37 public: 38 CFriend() 39 { 40 rp = rand()%10; 41 } 42 public: 43 void Play() 44 { 45 cout << "哈哈哈哈哈哈" << endl; 46 } 47 }; 48 49 50 51 class CPerson 52 { 53 public: 54 CHead head; // 组合 55 CHand hand; 56 CFriend* m_pFriend; // 关联一个朋友 57 public: 58 CPerson() 59 { 60 m_pFriend = 0; 61 } 62 public: 63 void FindFriend(CFriend* pFriend) 64 { 65 if(pFriend == 0) 66 return; 67 68 if(pFriend->rp > 4) 69 { 70 m_pFriend = pFriend; 71 } 72 } 73 void ChickenDinner() 74 { 75 if(m_pFriend == 0) 76 { 77 cout << "~~~~(>_<)~~~~玩的不开心" << endl; 78 } 79 else 80 { 81 m_pFriend->Play(); 82 } 83 } 84 void Say() 85 { 86 head.Say(); 87 hand.Move(); 88 } 89 void Coding(CComputer& cm) // 依赖一个电脑 90 { 91 head.Say(); 92 cm.Coding(); 93 } 94 }; 95 96 97 98 class CFamily 99 { 100 public: 101 CPerson* pArr[5]; // 聚合到 家庭中 102 public: 103 CFamily() 104 { 105 for(int i=0;i<5;i++) 106 pArr[i] = 0; 107 } 108 ~CFamily() 109 { 110 for(int i=0;i<5;i++) 111 { 112 if(pArr[i] != 0) 113 { 114 delete pArr[i]; 115 pArr[i] = 0; 116 } 117 } 118 } 119 public: 120 void PushPerson(CPerson* ps) 121 { 122 if(ps == 0) 123 return; 124 for(int i=0;i<5;i++) 125 { 126 if(pArr[i] == 0) 127 { 128 pArr[i] = ps; 129 return; 130 } 131 } 132 } 133 void AllPersonCoding(CComputer& cm) 134 { 135 for(int i=0;i<5;i++) 136 { 137 if(pArr[i] != 0) 138 { 139 pArr[i]->Coding(cm); 140 } 141 } 142 } 143 }; 144 145 146 147 148 int main() 149 { 150 151 //srand((unsigned int)time(0)); 152 153 //CComputer cm; 154 //CFriend ff; 155 156 //CPerson ps; 157 //ps.Say(); 158 //ps.Coding(cm); 159 160 //ps.FindFriend(&ff); 161 //ps.ChickenDinner(); 162 163 //-------------------------------------------------- 164 CPerson* ps1 = new CPerson; 165 CPerson* ps2 = new CPerson; 166 CPerson* ps3 = new CPerson; 167 168 CComputer cm; 169 CFamily fm; 170 fm.PushPerson(ps1); 171 fm.PushPerson(ps2); 172 fm.PushPerson(ps3); 173 fm.AllPersonCoding(cm); 174 175 system("pause"); 176 return 0; 177 }
而从纵向关系来看的关系有1.继承 2.多态
首先来说继承,继承中分为基类(父类),派生类(子类),继承的优点就是,提高代码的复用性,在派生类中,基类的所有成员都可以使用,而具体能否使用就得看继承的方式了
a.public继承,子类,public不变,protected不变,private变成不可访问的
b.protected 继承,子类,public->protected, protected不变, private变成不可访问的
c.private继承,子类,public->private, protected->private,private变成不可访问的
而需要注意的两点是
- 继承的方式影响的是派生类的派生类
- 继承的方式影响的只是基类的成员,不影响本类的访问修饰符
继承中还有一点就是继承关系的构造析构
- 继承里子类构造的初始化列表里默认为父类的初始化(很重要的一点)
- 局部顺序
子类构造->子类初始化列表->完成父类构造->完成子类构造->完成子类析构->回收子类空间->完成父类析构(在虚析构当中,虚函数完成的只是通过父类析构找到子类析构的过程,之后的过程和这个是一样的)
做一个小实验可以很好的看出来顺序
1 #include<iostream> 2 using namespace std; 3 4 class CPerson 5 { 6 public: 7 CPerson() 8 { 9 cout << "CPerson()" << endl; 10 } 11 ~CPerson() 12 { 13 cout << "~CPerson()" << endl; 14 } 15 }; 16 class CSon : public CPerson 17 { 18 public: 19 CSon() 20 { 21 cout << "CSon" << endl; 22 } 23 ~CSon() 24 { 25 cout << "~CSon" << endl; 26 } 27 }; 28 int main() 29 { 30 { 31 CSon cs; 32 } 33 34 35 36 system("pause"); 37 return 0; 38 }
第二个,多态,可以看一下上一篇帖子里 对于多态的讨论
2019-05-30 11:31:45 编程小菜鸟自我反思,大家可以留下自己的建议和意见,谢谢!!!