赞
踩
多态是C++面向对象三大特性之一
多态分为两类:
静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
动态多态: 派生类和虚函数实现运行时多态
静态多态和动态多态区别:
静态多态的函数地址早绑定-编译阶段确定函数地址
动态多态的函数地址晚绑定-运行阶段确定函数地址
下面通过案例进行讲解多态
1,静态多态的函数地址早绑定-编译阶段确定函数地址
- #include<iostream>
- using namespace std;
- //多态
-
- //动物类
- class Animal
- {
- public:
- void speak()
- {
- cout << "动物在说话" << endl;
- }
- };
-
- class Cat :public Animal
- {
- public:
- void speak()
- {
- cout << "小猫在说话" << endl;
- }
- };
-
- //执行说话的函数
- //静态多态的函数地址早绑定-编译阶段确定函数地址
- void doWork(Animal& animal)//Animal& animal = cat;
- {
- animal.speak();
- }
-
- void test()
- {
- Cat cat;
- doWork(cat);
- }
-
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
如果想执行让小猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段绑定,地址晚绑定
- #include<iostream>
- using namespace std;
- //多态
-
- //动物类
- class Animal
- {
- public:
- //虚函数 加上virtual变成虚函数,那么编译器在编译的时候就不能缺点函数调用了
- //那么就只能在运行时确认函数地址,则变成晚绑定
- virtual void speak()
- {
- cout << "动物在说话" << endl;
- }
- };
-
- //猫类
- class Cat :public Animal
- {
- public:
- //重写 函数返回值类型 函数名 参数列表 完全相同
- virtual void speak()
- {
- cout << "小猫在说话" << endl;
- }
- };
-
- class Dog :public Animal
- {
- public:
- void speak()
- {
- cout << "小狗在说话" << endl;
- }
- };
- //我们希望传入什么对象,那么就调用什么对象的函数
- //如果函数地址在编译结点就能缺点,那么静态联编
- //如果函数地址在运行时才能缺点,那么就是动态联编
-
- void doWork(Animal& animal)//Animal& animal = cat;
- {
- animal.speak();
- }
- //执行说话的函数
- //静态多态的函数地址早绑定-编译阶段确定函数地址
- //如果想执行让小猫说话,那么这个函数地址就不能提前绑定,需要在运行阶段绑定,地址晚绑定
-
- //动态多态满足条件:
- //1,有继承关系
- //2,子类出现父类的虚函数
-
- //动态多态使用
- //父类的指针或者引用 执行子类对象
- void test()
- {
- Cat cat;
- doWork(cat);
-
- Dog dog;
- doWork(dog);
- }
-
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
总结:多态满足条件
有继承关系
子类重写父类中的虚函数
多态使用条件:
父类指针或引用指向子类对象
重写:函数返回值类型 函数名 参数列表 完全一致称为重写
案例描述:
分别利用普通写法和多态技术,设计实现两个操作数进行运算的计算器类
多态的优点:
代码组织结构清晰
可读性强
利于前期和后期的扩展以及维护
示例:
普通实现:
- #include<iostream>
- using namespace std;
- class Calculator
- {
- public:
- int getResult(string oper)
- {
- if (oper == "+")
- {
- return m_Num1 + m_Num2;
- }
- else if (oper == "-")
- {
- return m_Num1 - m_Num2;
- }
-
- else if (oper == "*")
- {
- return m_Num1 * m_Num2;
- }
- else
- {
- return m_Num1 / m_Num2;
- }
- }
- int m_Num1;//操作数1
- int m_Num2;//操作数2
- };
-
- void test()
- {
- Calculator c;
- c.m_Num1 = 100;
- c.m_Num2 = 100;
-
- 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;
- }
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
多态实现:
如果想扩展新的功能,需要修改源码
在真实开发中,提供 开闭原则
开闭原则:对扩展进行开发,对修改进行关闭
- #include<iostream>
- using namespace std;
- #include<string>
-
- class AbstractCalculator
- {
- public:
- virtual int getResult()
- {
- return 0;
- }
- int m_Num1;//操作数1
- int m_Num2;//操作数2
- };
-
- class AddCalculator :public AbstractCalculator
- {
- int getResult()
- {
- return m_Num1 + m_Num2;
- }
- };
-
- class SubCalculator :public AbstractCalculator
- {
- int getResult()
- {
- return m_Num1 - m_Num2;
- }
- };
-
- class MulCalculator :public AbstractCalculator
- {
- int getResult()
- {
- return m_Num1 * m_Num2;
- }
- };
-
- class DivCalculator :public AbstractCalculator
- {
- int getResult()
- {
- return m_Num1 / m_Num2;
- }
- };
-
- void test()
- {
- //多态使用条件
- //父类制作或者引用指向子类对象
-
- AbstractCalculator* abs = new AddCalculator;
- abs->m_Num1 = 100;
- abs->m_Num2 = 100;
- cout << abs->m_Num1 << "+" << abs->m_Num2 << "=" << abs->getResult() << endl;
- //用完记得销毁
- delete abs;
-
- abs = new SubCalculator;
- abs->m_Num1 = 100;
- abs->m_Num2 = 100;
- cout << abs->m_Num1 << "-" << abs->m_Num2 << "=" << abs->getResult() << endl;
- //用完记得销毁
- delete abs;
-
- abs = new MulCalculator;
- abs->m_Num1 = 100;
- abs->m_Num2 = 100;
- cout << abs->m_Num1 << "*" << abs->m_Num2 << "=" << abs->getResult() << endl;
- //用完记得销毁
- delete abs;
-
- abs = new DivCalculator;
- abs->m_Num1 = 100;
- abs->m_Num2 = 100;
- cout << abs->m_Num1 << "/" << abs->m_Num2 << "=" << abs->getResult() << endl;
- //用完记得销毁
- delete abs;
- }
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
利用多态实现计算器//多态好处:
1、组织结构清晰
2、可读性强
3、对于前期和后期扩展以及维护性高
C++开发提出利用多态设计程序架构,因为多态优点很多
在多态中,通常父类中虚函数的实现是毫无意义的,主要都是调用子类重写的内容
因此可以将虚函数改为纯虚函数
纯虚函数语法:virtual 返回值类型 函数名(参数列表) = 0;
当类中有了纯虚函数,这个类也称为抽象类
抽象类特点:
无法实例化对象
子类必须重写抽象类中的纯虚函数,否则也属于抽象类
- #include<iostream>
- using namespace std;
- class Base
- {
- //纯虚函数
- //只要有一个纯虚函数,这个类就称为抽象类
- //抽象类特点:
- //1,无法实例化对象
- //2,抽象类的子类 必须要重写父类中的纯虚函数,否则也属于抽象类
- public:
- virtual void func() = 0;
-
- };
-
- class Son:public Base
- {
- public:
- virtual void func()
- {
- cout << "func 函数调用" << endl;
- };
-
- };
- void test()
- {
- //Base b;//抽象类无法实例化对象
- //new Base;//抽象类无法实例化对象
- Son s;//抽象类的子类 必须要重写父类中的纯虚函数,否则也属于抽象类
-
- Base * base = new Son;
- base->func();
- delete base;
- }
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
案例描述:
制作饮品的大致流程为:煮水-冲泡-倒入杯中-加入辅料
利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶
- #include<iostream>
- using namespace std;
-
- 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
- {
- public:
- //煮水
- virtual void Boil()
- {
- cout << "煮开水" << endl;
- }
-
- //冲泡
- virtual void Brew()
- {
- cout << "冲泡咖啡" << endl;
- }
-
- //倒入杯中
- virtual void PourInCup()
- {
- cout << "倒入杯中" << endl;
- }
-
- //加入辅料
- virtual void PutSomething()
- {
- cout << "加入牛奶和糖" << endl;
- }
- };
-
- //制作茶
- class Tea :public AbstractDrinking
- {
- public:
- //煮水
- 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 test()
- {
- //制作咖啡
- cout << "制作咖啡:" << endl;
- doWork(new Coffee);
-
- cout << "---------------------" << endl;
- cout << "制作茶:" << endl;
- //制作茶
- doWork(new Tea);
- }
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
虚析构和纯虚析构区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构函数的语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名()=0;
- #include<iostream>
- using namespace std;
- #include<string>
-
- //动物类
- class Animal
- {
- public:
- Animal()
- {
- cout << "Animal构造函数调用" << endl;
- }
- //利用虚析构函数可以解决 父类指针释放子类对象时不干净的问题
- //~Animal()
- //{
- // cout << "Animal析构函数调用" << endl;
- //}
-
- //纯虚析构 需要声明也需要实现
- //有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
- virtual ~Animal() = 0;
-
- //纯虚函数
- virtual void speak() = 0;
- };
- Animal:: ~Animal()
- {
-
- }
-
- //猫类
- class Cat :public Animal
- {
- public:
- Cat(string name)
- {
- cout << "Cat构造函数调用" << endl;
- m_Name = new string(name);
- }
- //重写 函数返回值类型 函数名 参数列表 完全相同
- virtual void speak()
- {
- cout << "小猫在说话" << endl;
- }
- ~Cat()
- {
- if (m_Name != NULL)
- {
- cout << "Cat析构函数调用" << endl;
- delete m_Name;
- m_Name = NULL;
- }
- }
- string *m_Name;
- };
-
-
- void doWork(Animal& animal)//Animal& animal = cat;
- {
- animal.speak();
- }
-
- void test()
- {
- Animal* animal = new Cat("Tom");
- animal->speak();
- //父类指针在析构时候,不会调用子类中析构函数,
- // 导致子类如果有堆区属性,出现内存泄露情况
- delete animal;
- }
-
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
总结:
1.虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2.如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3.拥有纯虚析构函数的类也属于抽象类
案例描述:
电脑主要组成部件为CPU(用于计算),显卡(用于显示),内存条(用于存储)将每个零件封装出抽象基
类,并且提供不同的厂商生产不同的零件,例如Intel厂商和Lenovo厂商创建电脑类提供让电脑工
作的函数,并且调用每个零件工作的接口测试时组装三台不同的电脑进行工作
- #include<iostream>
- using namespace std;
- #include<string>
-
- 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;
- }
-
- //提供工作函数
- void work()
- {
- //让零件工作起来,调用接口
- m_cpu->calculate();
-
- m_vc->display();
-
- m_mem->storage();
- }
-
- //提供析构函数 释放3个电脑零件
- ~Computer()
- {
- //释放cpu零件
- if (m_cpu != NULL)
- {
- delete m_cpu;
- m_cpu = NULL;
- }
-
- //释放显卡零件
- if (m_vc != NULL)
- {
- delete m_vc;
- m_vc = NULL;
- }
-
- //释放mem零件
- if (m_mem != NULL)
- {
- delete m_mem;
- m_mem = NULL;
- }
- }
-
-
-
- private:
- //构造函数中传入三个零件指针
- CPU * m_cpu;//CPU零件指针
- VideoCard * m_vc;//显卡零件指针
- Memory * m_mem;//内存条零件指针
-
- };
-
- //具体厂商
- //Inter厂商
- class InterCPU :public CPU
- {
- public:
- virtual void calculate()
- {
- cout << "Inter的COU开始计算!" << endl;
- }
- };
-
- class InterCard :public VideoCard
- {
- public:
- virtual void display()
- {
- cout << "Inter的显卡开始显示!" << endl;
- }
- };
-
- class InterMemory :public Memory
- {
- public:
- virtual void storage()
- {
- cout << "Inter的内存条开始存储!" << endl;
- }
- };
-
- //Lenovo厂商
- class LenovoCPU :public CPU
- {
- public:
- virtual void calculate()
- {
- cout << "Lenovo的COU开始计算!" << endl;
- }
- };
-
- class LenovoCard :public VideoCard
- {
- public:
- virtual void display()
- {
- cout << "Lenovo的显卡开始显示!" << endl;
- }
- };
-
- class LenovoMemory :public Memory
- {
- public:
- virtual void storage()
- {
- cout << "Lenovo的内存条开始存储!" << endl;
- }
- };
-
- void test01()
- {
- //第一台电脑的零件
- CPU* interCpu = new InterCPU;
- VideoCard* interCard = new InterCard;
- Memory* interMem = new InterMemory;
-
- //创建第一台电脑
- cout << "第一台电脑开始工作" << endl;
- Computer* computer1 = new Computer(interCpu, interCard, interMem);
- computer1->work();
- delete computer1;
-
- //第二台电脑组装
- cout << "------------------------" << endl;
- cout << "第二台电脑开始工作" << endl;
- Computer* computer2 = new Computer(new LenovoCPU, new LenovoCard, new LenovoMemory);
- computer2->work();
- delete computer2;
-
-
- //第三台电脑组装
- cout << "------------------------" << endl;
- cout << "第三台电脑开始工作" << endl;
- Computer* computer3 = new Computer(new LenovoCPU, new InterCard, new LenovoMemory);
- computer3->work();
- delete computer3;
- }
-
- int main()
- {
- test01();
-
- system("pause");
-
- return 0;
- }
程序运行时产生的数据都属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
C++中对文件操作需要包含头文件<fstream >
文件类型分为两种:
1.文本文件 文件以文本的ASCII码形式存储在计算机中
2.二进制文件- 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
操作文件的三大类:
1.ofstream:写操作
2.ifstream: 读操作
3.fstream : 读写操作
写文件步骤如下
1.包含头文件
#indude <fstream>
2. 创建流对象
ofstream ofs;
3. 打开文件
ofs.open("文件路径",打开方式);
4. 写数据
ofs<<"写入的数据”;
5.关闭文件
ofs.close();
文件打开方式:
打开方式 | 解释 |
---|---|
ios::in | 为读文件而打开文件 |
ios::out | 为写文件为打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 追加方式写文件 |
ios::trunc | 如果文件存在先删除,再船舰 |
ios::binary | 二进制方式 |
注意: 文件打开方式可以配合使用,利用 | 操作符
例如:用二进制方式写文件ios::binary | ios::out
代码展示:
- #include<iostream>
- using namespace std;
- #include<fstream>//头文件包含
-
- void test()
- {
- //1.包含头文件
- //#indude < fstream>
-
- //2. 创建流对象
- ofstream ofs;
-
- //3. 指定打开方式
- ofs.open("text.txt", ios::out);
-
- //4. 写数据
- ofs << "姓名:张三"<<endl;
- ofs << "年龄:18" << endl;
- ofs << "性别:男" << endl;
- //
- //5.关闭文件
- ofs.close();
- }
-
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
虽然再运行中未显示 ,但是打开text文件可以看到输入的内容
总结:
文件操作必须包含头文件 fstream
读文件可以利用 ofstream,或者fstream类
打开文件时候需要指定操作文件的路径,以及打开方式
利用<<可以向文件中写数据
操作完毕,要关闭文件
读文件与写文件步骤相似,但是读取方式相对于比较多
读文件步骤如下:
1.包含头文件
#include <fstream>
2.创建流对象
ifstream ifs;
3.打开文件并判断文件是否打开成功
ifs.open("文件路径",打开方式);
4. 读数据
四种方式读取
5.关闭文件
ifs.close();
示例:
- #include<iostream>
- using namespace std;
- #include<fstream>//头文件包含
- #include<string>
-
- void test()
- {
- //1.包含头文件
- //#indude < fstream>
-
- //2. 创建流对象
- ofstream ofs;//写文件
- ifstream ifs;//读文件
-
- //3. 指定打开方式
- ofs.open("text1.txt", ios::out);
- //4. 写数据
- ofs << "姓名:张三" << endl;
- ofs << "年龄:18" << endl;
- ofs << "性别:男" << endl;
-
- ifs.open("text1.txt", ios::in);
- if (!ifs.is_open())
- {
- cout << "文件打开失败" << endl;
- return;
- }
- // 读数据
-
- //第一种
- //char buf[1024] = { 0 };
- //while (ifs >> buf)
- //{
- // cout << buf << endl;
- //}
-
- //第二种
- char buf[1024] = { 0 };
- while (ifs.getline(buf,sizeof(buf)))
- {
- cout << buf << endl;
- }
-
- //第三种
- //string buf;
- //while ( getline(ifs, buf) )
- //{
- // cout << buf << endl;
- //}
-
- //第四种
- //char c;
- //while ((c = ifs.get()) != EOF)//EOF==end of file
- //{
- // cout << c;
- //}
- //5.关闭文件
- ifs.close();
- }
-
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
以二进制的方式对文件进行读写操作
打开方式要指定为 ios::binany
二进制方式写文件主要利用流对象调用成员函数write
函数原型:ostream& write(const char*buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
- #include<iostream>
- using namespace std;
- #include<fstream>//头文件包含
-
- class Person
- {
- public:
- char m_Name[64];
- int m_Age;
- };
-
- void test()
- {
- //1.包含头文件
- //#indude < fstream>
-
- //2. 创建流对象
- ofstream ofs("person.txt", ios::out | ios::binary);
-
- //3. 指定打开方式
- //ofs.open("person.txt", ios::out|ios::binary);
-
- //4. 写数据
- Person p = { "张三",18 };
- ofs.write((const char*)&p, sizeof(p));
-
- //5.关闭文件
- ofs.close();
- }
-
- int main()
- {
- test();
-
- system("pause");
-
- return 0;
- }
总结:
文件输出流对象 可以通过write函数,以二进制方式写数据
二进制方式读文件主要利用流对象调用成员函数read
函数原型:istream&read(char *buffer,int len);
参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数
示例:
- #include<iostream>
- using namespace std;
- #include<fstream>//头文件包含
-
- class Person
- {
- public:
- char m_Name[64];
- int m_Age;
- };
-
- void test01()
- {
- //1.包含头文件
- //#indude < fstream>
-
- //2. 创建流对象
- ofstream ofs("person.txt", ios::out | ios::binary);
-
- //3. 指定打开方式
- //ofs.open("person.txt", ios::out|ios::binary);
-
- //4. 写数据
- Person p = { "张三",18 };
- ofs.write((const char*)&p, sizeof(p));
-
- //5.关闭文件
- ofs.close();
- }
-
- void test02()
- {
- //1.包含头文件
- //#indude < fstream>
-
- //2. 创建流对象
- ifstream ifs;
-
- //3. 指定打开方式
- ifs.open("person.txt", ios::out|ios::binary);
- if (!ifs.is_open())
- {
- cout << "文件打开失败" << endl;
- return;
- }
- //4. 读数据
- Person p;
- ifs.read((char*)&p, sizeof(p));
- cout << "姓名:" << p.m_Name << "年龄:" << p.m_Age << endl;
- //5.关闭文件
- ifs.close();
- }
-
- int main()
- {
- test01();
-
- test02();
-
- system("pause");
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。