C++学习 --- 类和对象之多态
七、多态
1、多态的基本的概念
#include <iostream> #include <string> using namespace std; //多态 //动态多态满足条件 //1.有继承关系 //2.子类重写父类的虚函数 //重写:函数返回值类型,函数名,参数列表完全相同 //动态多态的使用 //父类的指针或者引用指向子类传入的对象 class Animal { public: //虚函数 virtual void speak() { cout << "动物在说话" << endl; } }; class Cat :public Animal { public: void speak() { cout << "小猫在说话" << endl; } }; class Dog: public Animal { public: void speak() { cout << "小狗在说话" << endl; } }; //执行说话的函数 //Animal 的引用接受子类的对象 //Animal &animal = cat; //地址早绑定,在编译阶段确定函数地址 //如果想执行猫说话,那个这个地址就不能提前绑定, //需要在运行阶段绑定,地址晚绑定,在Animal类的speak前加关键字virtual void doSpeak(Animal &animal) { animal.speak(); } void test01() { Cat cat; Dog dog; doSpeak(cat); doSpeak(dog); } //4个字节 void test02() { cout << "sizeof Animal = " << sizeof(Animal) << endl; } int main(){ test01(); test02(); system("pause"); return 0; }
父类Animal:
子类Cat 没有发生重写:
子类Cat 重写后:
2、多态案例一 计算器类
#include <iostream> #include <string> using namespace std; //分别利用普通的写法和多态技术实现计算器 //普通写法 class Calculator { public: int getResult(string oper) { if (oper == "+") { return m_Num1 + m_Num2; } if (oper == "-") { return m_Num1 - m_Num2; } if (oper == "*") { return m_Num1 * m_Num2; } if (oper == "/") { return m_Num1 / m_Num2; } //如果想扩展新的功能,需要修改源码 //在真实的开发中,开闭原则 //开闭原则:对扩展进行开放,对修改进行关闭 } int m_Num1; //操作数1 int m_Num2; //操作数2 }; void test01() { //创建计算器对象 Calculator c; c.m_Num1 = 10; c.m_Num2 = 10; cout << c.m_Num1 << "+" << c.m_Num2 << " = " << c.getResult("+") << endl; cout << c.m_Num1 << "-" << c.m_Num2 << " = " << c.getResult("-") << endl; cout << c.m_Num1 << "*" << c.m_Num2 << " = " << c.getResult("*") << endl; cout << c.m_Num1 << "/" << c.m_Num2 << " = " << c.getResult("/") << endl; } //利用多态实现计算器 //实现计算器的抽象类 class AbstractCalculator { public: virtual int getResult() { return 0; } int m_Num1; //操作数1 int m_Num2; //操作数2 }; //加法计算器类 class AddCalculator : public AbstractCalculator { public: int getResult() { return m_Num1 + m_Num2; } }; //减法计算器类 class SubCalculator : public AbstractCalculator { public: int getResult() { return m_Num1 - m_Num2; } }; //乘法计算器类 class MulCalculator : public AbstractCalculator { public: int getResult() { return m_Num1 * m_Num2; } }; void test02() { //多态使用条件 //父类指针或者引用指向子类对象 AbstractCalculator * abc = new AddCalculator; abc->m_Num1 = 10; abc->m_Num2 = 10; cout << abc->m_Num1 << "+" << abc->m_Num2 << " = " << abc->getResult() << endl; //使用完销毁指针堆区的数据 delete abc; abc = new SubCalculator; abc->m_Num1 = 100; abc->m_Num2 = 100; cout << abc->m_Num1 << "-" << abc->m_Num2 << " = " << abc->getResult() << endl; delete abc; abc = new MulCalculator; abc->m_Num1 = 10; abc->m_Num2 = 100; cout << abc->m_Num1 << "*" << abc->m_Num2 << " = " << abc->getResult() << endl; delete abc; } //多态带来的好处 //1.组织结构清晰 //2.可读性强 //3.对于前期和后期扩展及维护性高 int main(){ test01(); test02(); system("pause"); return 0; }
3、纯虚函数和抽象类
#include <iostream> #include <string> using namespace std; //纯虚函数和抽象类 class Base { public: //纯虚函数 virtual void func() = 0; //只要有一个纯虚函数,这个类称为抽象类 //抽象类特点: //1.无法实例化对象 //2.抽象类的子类,必须要重写父类中的纯虚函数,否则也属于抽象类 }; class Son1 :public Base { public : }; class Son2 :public Base { public: void func() { cout << "func 函数调用" << endl; } }; void test01() { //抽象类无法实例化对象 //Base b; //new Base; //子类未重写父类中的纯虚函数,属于抽象类,抽象类无法实例化对象 //Son1 s; //多态,使接口更通用化,通过同一个父类指针,由于指向的对象的不同,可以调用多种状态的函数。 Base * base = new Son2; base->func(); delete base; } int main(){ test01(); system("pause"); return 0; }
4、多态案例二 制作饮品
#include <iostream> #include <string> using namespace std; //多态的案例2 制作饮品 class AbstractDrinking { public: //煮水 virtual void Boil() = 0; //冲泡 virtual void Brew() = 0; //倒入杯中 virtual void PourInCup() = 0; //加入辅料 virtual void PutSomething() = 0; //制作饮品 void makeDrink() { Boil(); Brew(); PourInCup(); PutSomething(); } }; //制作咖啡 class Coffee:public AbstractDrinking { //煮水 virtual void Boil() { cout << "煮农夫山泉水" << endl; } //冲泡 virtual void Brew() { cout << "冲泡咖啡" << endl; } //倒入杯中 virtual void PourInCup() { cout << "倒入咖啡杯中" << endl; } //加入辅料 virtual void PutSomething() { cout << "加入糖和牛奶" << endl; } }; //制作茶叶 class Tea :public AbstractDrinking { //煮水 virtual void Boil() { cout << "煮矿泉水" << endl; } //冲泡 virtual void Brew() { cout << "冲泡茶叶" << endl; } //倒入杯中 virtual void PourInCup() { cout << "倒入茶杯中" << endl; } //加入辅料 virtual void PutSomething() { cout << "加入枸杞" << endl; } }; //制作函数 void doWork(AbstractDrinking * abs) { abs->makeDrink(); delete abs; } void test01() { //制作咖啡 doWork(new Coffee); cout << "-------------------" << endl; //制作茶 doWork(new Tea); } int main(){ test01(); system("pause"); return 0; }
5、虚析构和纯虚析构
#include <iostream> #include <string> using namespace std; //虚析构和纯虚析构 class Animal { public: Animal() { cout << "Animal 构造函数调用" << endl; } //纯虚函数 virtual void speak() = 0; //析构改为虚析构,会走子类中的代码 //利用虚析构可以解决,父类指针释放子类对象时堆区释放不完整的问题 /*virtual ~Animal() { cout << "Animal 析构函数调用" << endl; }*/ //纯虚析构 //纯虚析构和虚析构只能有一个 //纯虚析构需要声明也需要实现,若无实现:在链接阶段出现 “无法解析的外部符号LNK2019” //有个纯虚析构之后,这个类也属于抽象类,无法实例化对象。 virtual ~Animal() = 0; }; //为什么要实现,因为父类中也有代码属性开辟到堆区的情况,要求实现 Animal::~Animal() { cout << "Animal 纯析构函数调用" << endl; } class Cat :public Animal { public: Cat(string name) { cout << "Cat 的构造函数调用" << endl; m_Name = new string(name); } void speak() { cout << *m_Name << "小猫在说话" << endl; } ~Cat() { if (m_Name != NULL) { cout << "Cat 的析构函数调用" << endl; delete m_Name; m_Name = NULL; } } string * m_Name; }; void test01() { Animal * animal = new Cat("Tom"); animal->speak(); delete animal; //父类指针在析构时 不会调用子类中析构函数,导致子类如果有堆区属性,会出现内存泄露 //利用虚析构可以解决,父类指针释放子类对象时堆区释放不完整的问题 } int main(){ test01(); system("pause"); return 0; }
6、多态案例三 电脑组装
#include <iostream> #include <string> using namespace std; //抽象出不同零件类 //抽象cpu类 class CPU { public: //抽象的计算函数 virtual void calculate() = 0; }; //抽象显卡类 class VideoCard { public: //抽象的显示函数 virtual void display() = 0; }; //抽象内存类 class Memory { public: //抽象的存储函数 virtual void storage() = 0; }; //电脑类 class Computer { public: Computer(CPU *cpu, VideoCard *vc, Memory * mem) { m_cpu = cpu; m_vc = vc; m_mem = mem; } ~Computer() { //释放cpu零件 if (m_cpu != NULL) { delete m_cpu; m_cpu = NULL; } //释放显卡零件 if (m_vc != NULL) { delete m_vc; m_vc = NULL; } //释放内存零件 if (m_mem != NULL) { delete m_mem; m_mem = NULL; } } //提供工作的函数 void work() { m_cpu->calculate(); m_vc->display(); m_mem->storage(); } private: CPU * m_cpu; //cpu的零件指针 VideoCard * m_vc; //显卡的零件指针 Memory *m_mem; //内存的零件指针 }; //具体的厂商 //Intel厂商 class IntelCPU :public CPU { public: virtual void calculate() { cout << "Intel 的cpu开始 计算了!" << endl; } }; class IntelVideoCard :public VideoCard { public: virtual void display() { cout << "Intel 的显卡开始 显示了!" << endl; } }; class IntelMemory :public Memory { public: virtual void storage() { cout << "Intel 的内存条开始 存储了!" << endl; } }; //Lenovo厂商 class LenovoCPU :public CPU { public: virtual void calculate() { cout << "Lenovo 的cpu开始 计算了!" << endl; } }; class LenovoVideoCard :public VideoCard { public: virtual void display() { cout << "Lenovo 的显卡开始 显示了!" << endl; } }; class LenovoMemory :public Memory { public: virtual void storage() { cout << "Lenovo 的内存条开始 存储了!" << endl; } }; void test01() { //第一台电脑零件 CPU * intelCPU = new IntelCPU; VideoCard *intelCard = new IntelVideoCard; Memory * intelMem = new IntelMemory; //创建第一台电脑 cout << "第一台电脑开始工作:" << endl; Computer * computer1 = new Computer(intelCPU, intelCard, intelMem); computer1->work(); delete computer1; //第二台电脑组装 cout << "--------------" << endl; cout << "第二台电脑开始工作:" << endl; Computer * computer2 = new Computer(new LenovoCPU, new LenovoVideoCard, new LenovoMemory); computer2->work(); delete computer2; //第三台电脑组装 cout << "--------------" << endl; cout << "第三台电脑开始工作:" << endl; Computer * computer3 = new Computer(new LenovoCPU, new IntelVideoCard, new LenovoMemory); computer3->work(); delete computer3; } int main(){ test01(); system("pause"); return 0; }