c++基础学习笔记——04-c++day07
在学习c++基础总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
04-c++day07
目录:
一、类和对象——多态
1、静态联编和动态联编
2、多态原理解析
3、多态深入剖析锻炼
4、多态案例——计算器案例
5、抽象类和纯虚函数
6、虚析构和纯虚析构函数
7、向上类型转换和向下类型转换
8、多态案例——pk游戏
(1)游戏需求
(2)游戏构建
(3)游戏运行
二、总结
一、类和对象——多态
多态基本概念
多态是面向对象程序设计语言中数据抽象和继承之外的第三个基本特征。
多态性(polymorphism)提供接口与具体实现之间的另一层隔离,从而将”what”和”how”分离开来。多态性改善了代码的可读性和组织性,同时也使创建的程序具有可扩展性,项目不仅在最初创建时期可以扩展,而且当项目在需要有新的功能时也能扩展。
c++支持编译时多态(静态多态)和运行时多态(动态多态),运算符重载和函数重载就是编译时多态,而派生类和虚函数实现运行时多态。
静态多态和动态多态的区别就是函数地址是早绑定(静态联编)还是晚绑定(动态联编)。如果函数的调用,在编译阶段就可以确定函数的调用地址,并产生代码,就是静态多态(编译时多态),就是说地址是早绑定的。而如果函数的调用地址不能编译不能在编译期间确定,而需要在运行时才能决定,这这就属于晚绑定(动态多态,运行时多态)。
1、静态联编和动态联编
练习:
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 9 virtual void speak() 10 { 11 cout << "动物在说话" << endl; 12 } 13 14 }; 15 16 class Cat:public Animal 17 { 18 public: 19 20 void speak() 21 { 22 cout << "小猫在说话" << endl; 23 } 24 25 26 } 27 28 //调用doSpeak,speak函数的地址早就绑定好了,早绑定,静态联编,编译阶段就确定好了地址 29 //如果想调用猫的speak,不能提前绑定好函数的地址了,所以需要在运行时候再去确定函数地址 30 //动态联编,写法Dospeak方法改为虚函数,在父类上声明虚函数,发生了多态 31 //(多态)父类的引用或者指针 指向 子类对象 32 void doSpeak(Animal& animal)//Animal& animal = cat; 33 { 34 animal.speak(); 35 } 36 37 //如果发生了继承的关系,编译器允许进行类型转换 38 void test01() 39 { 40 Cat cat; 41 doSpeak(cat); 42 43 } 44 45 int main() 46 { 47 test01(); 48 49 system("pause"); 50 return EXIT_SUCCESS; 51 }
2、多态原理解析
当父类中有了虚函数后,内部结构就发生了改变,内部多了一个 vfprt,virtual function pointer 虚函数表指针,指向 vftable 虚函数表。
查看类内部结构:
Animal类:
Cat类中没有void speak()函数时:
Cat类中加入void speak()函数时:
测试:
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 9 virtual void speak() 10 { 11 cout << "动物在说话" << endl; 12 } 13 14 }; 15 16 class Cat:public Animal 17 { 18 public: 19 20 void speak()//子类中的virtual可写可不写 21 { 22 cout << "小猫在说话" << endl; 23 } 24 25 26 } 27 28 //调用doSpeak,speak函数的地址早就绑定好了,早绑定,静态联编,编译阶段就确定好了地址 29 //如果想调用猫的speak,不能提前绑定好函数的地址了,所以需要在运行时候再去确定函数地址 30 //动态联编,写法Dospeak方法改为虚函数,在父类上声明虚函数,发生了多态 31 //(多态)父类的引用或者指针 指向 子类对象 32 void doSpeak(Animal& animal)//Animal& animal = cat; 33 { 34 animal.speak(); 35 } 36 37 //如果发生了继承的关系,编译器允许进行类型转换 38 void test01() 39 { 40 Cat cat; 41 doSpeak(cat); 42 43 } 44 45 void test02() 46 { 47 //cout << sizeof(Animal) << endl; 48 49 //父类指针指向子类对象 多态 50 Animal* animal = new Cat; 51 52 //animal->speak(); 53 //*(int*)*(int*)animal 函数地址 54 ((void(*)())(*(int*)*(int*)animal))(); 55 } 56 57 58 int main() 59 { 60 test01(); 61 62 system("pause"); 63 return EXIT_SUCCESS; 64 }
3、多态深入剖析锻炼
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 9 virtual void speak() 10 { 11 cout << "动物在说话" << endl; 12 } 13 14 virtual void eat() 15 { 16 cout << "动物在吃饭" << endl; 17 } 18 19 }; 20 21 class Cat:public Animal 22 { 23 public: 24 25 void speak()//子类中的virtual可写可不写 26 { 27 cout << "小猫在说话" << endl; 28 } 29 30 virtual void eat() 31 { 32 cout << "小猫在吃鱼" << endl; 33 } 34 35 } 36 37 //调用doSpeak,speak函数的地址早就绑定好了,早绑定,静态联编,编译阶段就确定好了地址 38 //如果想调用猫的speak,不能提前绑定好函数的地址了,所以需要在运行时候再去确定函数地址 39 //动态联编,写法Dospeak方法改为虚函数,在父类上声明虚函数,发生了多态 40 //(多态)父类的引用或者指针 指向 子类对象 41 void doSpeak(Animal& animal)//Animal& animal = cat; 42 { 43 animal.speak(); 44 } 45 46 //如果发生了继承的关系,编译器允许进行类型转换 47 void test01() 48 { 49 Cat cat; 50 doSpeak(cat); 51 52 } 53 54 void test02() 55 { 56 //cout << sizeof(Animal) << endl; 57 58 //父类指针指向子类对象 多态 59 Animal* animal = new Cat; 60 61 //animal->speak(); 62 //*(int*)*(int*)animal 函数地址 63 ((void(*)())(*(int*)*(int*)animal))(); 64 65 //*((int*)*(int*)animal + 1)猫在吃鱼的地址 66 ((void(*)())(*((int*)*(int*)animal + 1)))(); 67 } 68 69 70 int main() 71 { 72 test01(); 73 74 system("pause"); 75 return EXIT_SUCCESS; 76 }
4、多态案例——计算器案例
早期方法 是不利于扩展;开发有原则 开闭原则 -- 对扩展开放 对修改关闭;利用多态实现 – 利于后期扩展,结构性非常好,可读性高, 效率稍微低,发生多态内部结构复杂。
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 #include<string> 4 using namespace std; 5 6 /* 7 class Calculator 8 { 9 public: 10 11 void setv1(int v) 12 { 13 this->val1 = v; 14 } 15 void setv2(int v) 16 { 17 this->val2 = v; 18 } 19 20 int getResult(string oper) 21 { 22 if(oper == "+") 23 { 24 return val1 + val2; 25 } 26 else if(oper == "-") 27 { 28 return val1 - val2; 29 } 30 31 32 } 33 private: 34 int val1; 35 int val2; 36 }; 37 38 39 void test01() 40 { 41 Calculator cal; 42 cal.setv1(10); 43 cal.setv2(10); 44 cout << cal.getResult("+") << endl; 45 cout << cal.getResult("-") << endl; 46 } 47 */ 48 49 //真正的开发中,有个开发原则——开闭原则 50 //对扩展开放,对修改关闭 51 52 //利用多态实现计算器 53 class abstractCalculator 54 { 55 public: 56 virtual int getResult(){ return 0;}; 57 58 void setv1(int v) 59 { 60 this->val1 = v; 61 } 62 void setv2(int v) 63 { 64 this->val2 = v; 65 } 66 67 public: 68 int val1; 69 int val2; 70 71 }; 72 //加法计算器 73 class PlusCalculator:public abstractCalculator 74 { 75 public: 76 virtual int getResult() 77 { 78 return val1 + val2; 79 } 80 81 }; 82 //减法计算器 83 class SubCalculator:public abstractCalculator 84 { 85 public: 86 virtual int getResult() 87 { 88 return val1 - val2; 89 } 90 91 }; 92 93 //扩展 94 //乘法计算器 95 class ChengCalculator:public abstractCalculator 96 { 97 public: 98 virtual int getResult() 99 { 100 return val1 * val2; 101 } 102 103 }; 104 void test01() 105 { 106 abstractCalculator* abc; 107 //加法计算器 108 abc = new PlusCalculator; 109 110 abc->setv1(10); 111 abc->setv2(20); 112 113 cout << abc->getResult() << endl; 114 115 delete abc; 116 117 //减法计算器 118 abc = new SubCalculator; 119 120 abc->setv1(10); 121 abc->setv2(20); 122 123 cout << abc->getResult() << endl; 124 125 delete abc; 126 127 //乘法计算器 128 abc = new ChengCalculator; 129 130 abc->setv1(10); 131 abc->setv2(20); 132 133 cout << abc->getResult() << endl; 134 } 135 136 int main() 137 { 138 test01(); 139 140 system("pause"); 141 return EXIT_SUCCESS; 142 }
5、抽象类和纯虚函数
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 #include<string> 4 using namespace std; 5 6 /* 7 class Calculator 8 { 9 public: 10 11 void setv1(int v) 12 { 13 this->val1 = v; 14 } 15 void setv2(int v) 16 { 17 this->val2 = v; 18 } 19 20 int getResult(string oper) 21 { 22 if(oper == "+") 23 { 24 return val1 + val2; 25 } 26 else if(oper == "-") 27 { 28 return val1 - val2; 29 } 30 31 32 } 33 private: 34 int val1; 35 int val2; 36 }; 37 38 39 void test01() 40 { 41 Calculator cal; 42 cal.setv1(10); 43 cal.setv2(10); 44 cout << cal.getResult("+") << endl; 45 cout << cal.getResult("-") << endl; 46 } 47 */ 48 49 //真正的开发中,有个开发原则——开闭原则 50 //对扩展开放,对修改关闭 51 52 //利用多态实现计算器 53 class abstractCalculator 54 { 55 public: 56 57 //虚函数virtual int getResult(){ return 0;}; 58 59 //纯虚函数 60 //1.如果父类中有了纯虚函数,子类继承父类,就必须要实现纯虚函数 61 //2.如果父类中有了纯虚函数,这个父类就无法实例化对象了 62 //3.这个类有了纯虚函数,通常又称为抽象类 63 virtual int getResult() = 0; 64 65 66 void setv1(int v) 67 { 68 this->val1 = v; 69 } 70 void setv2(int v) 71 { 72 this->val2 = v; 73 } 74 75 public: 76 int val1; 77 int val2; 78 79 }; 80 //如果父类中有了纯虚函数,子类继承父类,就必须要实现纯虚函数 81 class A:public abstractCalculator 82 { 83 virtual int getResult() 84 { 85 return 0; 86 } 87 } 88 89 //加法计算器 90 class PlusCalculator:public abstractCalculator 91 { 92 public: 93 virtual int getResult() 94 { 95 return val1 + val2; 96 } 97 98 }; 99 //减法计算器 100 class SubCalculator:public abstractCalculator 101 { 102 public: 103 virtual int getResult() 104 { 105 return val1 - val2; 106 } 107 108 }; 109 110 //扩展 111 //乘法计算器 112 class ChengCalculator:public abstractCalculator 113 { 114 public: 115 virtual int getResult() 116 { 117 return val1 * val2; 118 } 119 120 }; 121 void test01() 122 { 123 abstractCalculator* abc; 124 //加法计算器 125 abc = new PlusCalculator; 126 127 abc->setv1(10); 128 abc->setv2(20); 129 130 cout << abc->getResult() << endl; 131 132 delete abc; 133 134 //减法计算器 135 abc = new SubCalculator; 136 137 abc->setv1(10); 138 abc->setv2(20); 139 140 cout << abc->getResult() << endl; 141 142 delete abc; 143 144 //乘法计算器 145 abc = new ChengCalculator; 146 147 abc->setv1(10); 148 abc->setv2(20); 149 150 cout << abc->getResult() << endl; 151 152 //1.如果父类中有了纯虚函数,子类继承父类,就必须要实现纯虚函数 153 //A a; 154 155 //2.如果父类中有了纯虚函数,这个父类就无法实例化对象了 156 //abstractCalculator aaa; 157 //abstractCalculator* abc = new abstractCalculator; 158 } 159 160 int main() 161 { 162 test01(); 163 164 system("pause"); 165 return EXIT_SUCCESS; 166 }
6、虚析构和纯虚析构函数
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 using namespace std; 4 5 class Animal 6 { 7 public: 8 9 virtual void speak() 10 { 11 cout << "动物在说话" << endl; 12 } 13 14 //普通析构,是不会调用子类的析构的,所以可能会导致释放不干净 15 //利用虚析构来解决这个问题 16 /* 17 virtual ~Animal() 18 { 19 cout << "Animal的析构调用" << endl; 20 } 21 */ 22 23 //纯虚析构,写法如下 24 //纯虚析构,需要声明,还需要实现(类内声明,类外实现) 25 virtual ~Animal() = 0; 26 //如果函数中出现了纯虚析构函数,那么这个类也算抽象类 27 //抽象类,不可以实例化对象 28 }; 29 Animal::~Animal() 30 { 31 //纯虚析构函数实现 32 cout << "Animal的纯虚析构调用" << endl; 33 } 34 //如果出现纯虚析构,类也算抽象类,不能实例化对象 35 //void func() 36 //{ 37 // Animal an; 38 // Animal* animal = new Animal; 39 //} 40 41 42 class Cat:public Animal 43 { 44 public: 45 Cat(const char* name) 46 { 47 this->m_Name = new char[strlen(name) + 1]; 48 strcpy(this->m_Name, name); 49 } 50 51 virtual void speak() 52 { 53 cout << "小猫在说话" << endl; 54 } 55 56 ~Cat() 57 { 58 cout << "Cat的析构调用" << endl; 59 if(this->m_Name != NULL) 60 { 61 delete[] this->m_Name; 62 this->m_Name = NULL; 63 } 64 } 65 66 char* m_Name; 67 }; 68 69 void test01() 70 { 71 Animal* animal = new Cat("Tom"); 72 animal->speak(); 73 74 delete animal; 75 76 } 77 78 int main() 79 { 80 test01(); 81 82 system("pause"); 83 return EXIT_SUCCESS; 84 }
7、向上类型转换和向下类型转换
8、多态案例——pk游戏
(1)游戏需求
(2)游戏构建
多态案例—PK小游戏.cpp
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<iostream> 3 #include"Hero.h" 4 #include"Monster.h" 5 #include"Weapon.h" 6 #include"Knife.h" 7 #include"DragonSword.h" 8 #include<ctime> 9 using namespace std; 10 11 12 void play() 13 { 14 //创建怪物 15 Monster* monster = new Monster; 16 //创建英雄 17 Hero* hero = new Hero; 18 19 //创建武器 20 Weapon* knife = new Knife; 21 Weapon* dragon = new DragonSword; 22 23 //让用户选择武器 24 cout << "请选择武器:" << endl; 25 cout << "1.赤手空拳" << endl; 26 cout << "2.小刀" << endl; 27 cout << "3.屠龙刀" << endl; 28 29 int oper; 30 cin >> oper; 31 32 switch(oper) 33 { 34 case 1: 35 cout << "你真牛X,你还是太年轻了!" << endl; 36 break; 37 case 2: 38 hero->EquipWeapon(knife); 39 break; 40 case 3: 41 hero->EquipWeapon(dragon); 42 break; 43 } 44 45 getchar();//输入缓存区里有个回车,多获取一次值 46 47 int round = 1; 48 49 while(true) 50 { 51 getchar(); 52 53 system("cls"); 54 55 cout << "------当前第 " << round << "回合开始--------" << endl; 56 57 if(hero->m_Hp <= 0) 58 { 59 cout << "英雄" << hero->m_Name << "已挂,游戏结束" << endl; 60 break; 61 } 62 hero->Attack(monster); 63 if(monster->m_Hp <= 0) 64 { 65 cout << "怪物" << monster->m_Name << "已挂,顺利通关" << endl; 66 break; 67 } 68 monster->Attack(hero); 69 70 if(hero->m_Hp <= 0) 71 { 72 cout << "英雄" << hero->m_Name << "已挂,游戏结束" << endl; 73 break; 74 } 75 76 cout << "英雄" << hero->m_Name << "剩余血量:" << hero->m_Hp << endl; 77 cout << "怪物" << monster->m_Name << "剩余血量:" << monster->m_Hp << endl; 78 79 round++; 80 } 81 82 delete monster; 83 delete hero; 84 delete knife; 85 delete dragon; 86 87 } 88 89 int main() 90 { 91 srand((unsigned int)time(NULL)); 92 93 play(); 94 95 system("pause"); 96 return EXIT_SUCCESS; 97 }
Weapon.h
#pragma once #include<iostream> #include<string> using namespace std; //抽象类 class Weapon { public: //获取基础伤害 virtual int getBaseDemage() = 0; //获取吸血 virtual int getSuckBlood() = 0; //获取是否定身 virtual bool getHold() = 0; //获取是否暴击 virtual bool getCrit() = 0; string m_WeaponName;//武器名称 int m_BaseDemage;//基础伤害 };
Knife.h
1 #pragma once 2 #include<iostream> 3 #include<string> 4 #include"Weapon.h" 5 using namespace std; 6 7 class Knife:public Weapon 8 { 9 public: 10 Knife(); 11 12 //获取基础伤害 13 virtual int getBaseDemage(); 14 15 //获取吸血 16 virtual int getSuckBlood(); 17 18 //获取是否定身 19 virtual bool getHold(); 20 21 //获取是否暴击 22 virtual bool getCrit(); 23 24 25 26 };
Knife.cpp
1 #include"Knife.h" 2 3 4 Knife::Knife() 5 { 6 this->m_BaseDamage = 10; 7 8 this->m_WeaponName = "小刀"; 9 } 10 11 //获取基础伤害 12 int Knife::getBaseDemage() 13 { 14 return this->m_BaseDamage; 15 } 16 17 //获取吸血 18 int Knife::getSuckBlood() 19 { 20 return 0; 21 } 22 23 //获取是否定身 24 bool Knife::getHold() 25 { 26 return false; 27 } 28 29 //获取是否暴击 30 bool Knife::getCrit() 31 { 32 return false; 33 }
DragonSword.h
1 #pragma once 2 #include<iostream> 3 #include<string> 4 #include"Weapon.h" 5 using namespace std; 6 7 class DragonSword:public Weapon 8 { 9 public: 10 DragonSword(); 11 12 //获取基础伤害 13 virtual int getBaseDemage(); 14 15 //获取吸血 16 virtual int getSuckBlood(); 17 18 //获取是否定身 19 virtual bool getHold(); 20 21 //获取是否暴击 22 virtual bool getCrit(); 23 24 //吸血率 暴击率 定身率 25 int suckRate; 26 int holdRate; 27 int critRate; 28 29 //传入概率,判断是否触发 30 bool isTrigger(int rate); 31 };
DragonSword.cpp
1 #include"DragonSword.h" 2 3 DragonSword::DragonSword() 4 { 5 this->m_BaseDamage = 20; 6 this->m_WeaponName = "屠龙宝刀"; 7 this->suckRate = 20; 8 this->holdRate = 30; 9 this->critRate = 35; 10 } 11 12 //获取基础伤害 13 int DragonSword::getBaseDemage() 14 { 15 return this->m_BaseDamage; 16 } 17 18 //获取吸血 19 int DragonSword::getSuckBlood() 20 { 21 if(isTrigger(suckRate)) 22 { 23 return this->m_BaseDamage * 0.5;//按照武器基础伤害一半吸血 24 } 25 return 0; 26 } 27 28 //获取是否定身 29 bool DragonSword::getHold() 30 { 31 if(isTrigger(holdRate)) 32 { 33 return true; 34 } 35 return false; 36 } 37 38 //获取是否暴击 39 bool DragonSword::getCrit() 40 { 41 if(isTrigger(critRate)) 42 { 43 return true; 44 } 45 return false; 46 } 47 48 49 //传入概率,判断是否触发 50 bool DragonSword::isTrigger(int rate) 51 { 52 //通过isTrigger判断是否触发特效 53 //随机0~100的数字 54 int num = rand() % 100 + 1; 55 if(num < rate) 56 { 57 return true; 58 } 59 return false; 60 }
Hero.h
1 #pragma once 2 #include<iostream> 3 #include<string> 4 #include"Weapon.h" 5 #include"Monster.h" 6 using namespace std; 7 8 class Monster; 9 class Hero 10 { 11 public: 12 Hero(); 13 14 string m_Name;//人名 15 16 int m_Atk;//攻击力 17 18 int m_Def;//防御力 19 20 int m_Hp;//血量 21 22 Weapon* weapon;//武器 23 24 void EquipWeapon(Weapon* weapon); 25 26 void Attack(Monster* monster); 27 };
Hero.cpp
1 #include"Hero.h" 2 3 Hero::Hero() 4 { 5 this->m_Hp = 500; 6 this->m_Atk = 50; 7 this->m_Def = 50; 8 this->m_Name = "刘法师"; 9 this->weapon = NULL; 10 } 11 12 //装备武器 13 void Hero::EquipWeapon(Weapon* weapon) 14 { 15 this->weapon = weapon; 16 cout << "英雄:" << this->m_Name << "装备了武器《" << this->weapon->m_WeaponName << " 》" << endl; 17 } 18 //攻击 19 void Hero::Attack(Monster* monster) 20 { 21 int damage = 0; 22 int addHp = 0; 23 bool isHold = false; 24 bool isCrit = false; 25 26 if(this->weapon = NULL)//武器为空,没有加成 27 { 28 damage = this->m_Atk; 29 } 30 else 31 { 32 //基础伤害 33 damage = this->m_Atk + this->weapon->getBaseDamage(); 34 //计算吸血 35 addHp = this->weapon->getSuckBlood(); 36 //计算定身 37 isHold = this->weapon->getHold(); 38 //计算暴击 39 isCrit = this->weapon->getCrit(); 40 } 41 if(isCrit)//暴击,伤害加成 42 { 43 damage = damage * 2; 44 cout << "英雄的武器触发了暴击效果,怪物受到了双倍的伤害,伤害值为:" << damage << endl; 45 } 46 if(isHold)//定身 47 { 48 cout << "英雄的武器触发了定身效果,怪物停止攻击一回合" << endl; 49 } 50 if(addHp > 0)//暴击,伤害加成 51 { 52 cout << "英雄的武器触发了吸血效果,英雄增加的血量为:" << addHp << endl; 53 } 54 55 //设置怪物定身 56 monster->m_Hold = isHold; 57 58 //计算真实伤害 59 int trueDamage = (damage - monster->m_Def) > 0 ? damage - monster->m_Def : 1; 60 61 //怪物掉血 62 monster->m_Hp -= trueDamage; 63 64 //英雄吸血 65 this->m_Hp += addHp; 66 67 cout << "英雄" << this->m_Name << "攻击了敌人" << monster->m_Name << "造成了伤害" << trueDamage << endl; 68 }
Monster.h
1 #pragma once 2 #include<iostream> 3 #include<string> 4 #include"Weapon.h" 5 #include"Hero.h" 6 using namespace std; 7 8 class Hero; 9 class Monster 10 { 11 public: 12 Monster(); 13 14 string m_Name; 15 16 int m_Hp; 17 18 int m_Atk; 19 20 int m_Def; 21 22 bool m_Hold; 23 24 void Attack(Hero* hero); 25 26 };
Monster.cpp
1 #include"Monster.h" 2 3 4 Monster::Monster() 5 { 6 this->m_Hp = 300; 7 8 this->m_Atk = 70; 9 10 this->m_Def = 40; 11 12 this->m_Hold = false; 13 14 this->m_Name = "比克大魔王"; 15 } 16 17 void Monster::Attack(Hero* hero) 18 { 19 if(this->m_Hold) 20 { 21 cout << "怪物" << this->m_Name << "被定身了,本回合无法攻击" << endl; 22 return; 23 } 24 25 //计算攻击伤害 26 int damage = (this->m_Atk - hero->m_Def) > 0 ? this->m_Atk - hero->m_Def : 1; 27 28 hero->m_Hp -= damage; 29 30 cout << "怪物" << this->m_Name << "攻击了英雄" << hero->m_Name << "造成了伤害" << damage << endl; 31 }
(3)游戏运行
二、总结
1 静态联编和动态联编
1.1 多态分类
1.1.1 静态多态 函数重载
1.1.2 动态多态 虚函数 继承关系
1.2 静态联编
1.2.1 地址早绑定 编译阶段绑定好地址
1.3 动态联编
1.3.1 地址晚绑定 ,运行时候绑定好地址
1.4 多态
1.4.1 父类的引用或指针指向子类对象
2 多态原理解析
2.1 当父类中有了虚函数后,内部结构就发生了改变
2.2 内部多了一个 vfprt
2.2.1 virtual function pointer 虚函数表指针
2.2.2 指向 vftable 虚函数表
2.3 父类中结构 vfptr &Animal::speak
2.4 子类中 进行继承 会继承 vfptr vftable
2.5 构造函数中 会将虚函数表指针 指向自己的虚函数表
2.6 如果发生了重写,会替换掉虚函数表中的原有的speak,改为 &Cat::speak
2.7 深入剖析,内部到底如何调用
2.8 ((void(*)()) (*(int*)*(int*)animal))();
2.9 猫吃鱼的函数调用(编译器的调用)
3 多态案例 – 计算器案例
3.1 早期方法 是不利于扩展
3.2 开发有原则 开闭原则 -- 对扩展开放 对修改关闭
3.3 利用多态实现 – 利于后期扩展,结构性非常好,可读性高, 效率稍微低,发生多态内部结构复杂
4 抽象类 和 纯虚函数
4.1 纯虚函数写法 virtual void func() = 0;
4.2 抽象类型
4.3 抽象类 不可以实例化对象
4.4 如果类 继承了抽象类, 必须重写抽象类中的纯虚函数
5 虚析构和纯虚析构
5.1 虚析构
5.1.1 virtual ~类名() {}
5.1.2 解决问题: 通过父类指针指向子类对象释放时候不干净导致的问题
5.2 纯虚析构函数
5.2.1 写法 virtual ~类名() = 0
5.2.2 类内声明 类外实现
5.2.3 如果出现了纯虚析构函数,这个类也算抽象类,不可以实例化对象
6 向上类型转换和向下类型转换
6.1 基类转派生类
6.1.1 向下类型转换 不安全的
6.2 派生类转 基类
6.2.1 向上类型转换 安全
6.3 如果发生多态
6.3.1 总是安全的
6.4 父类中如果写了虚函数,而子类没有任何重写,有意义吗?
6.4.1 没有意义
在学习c++基础总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。
posted on 2020-06-14 09:02 Alliswell_WP 阅读(222) 评论(0) 编辑 收藏 举报