5,411
社区成员




例如:同为人类的理发师和演员,当执行 cut 操作时,理发师的行为是剪发,演员的行为是停止表演,不同的对象,所表现的行为是不一样的
多态分为两类:
静态多态:>函数重载 和 运算符重载属于静态多态,复用函数名
动态多态:派生类和虚函数实现运行时多态
静态多态和动态多态的区别:
#include<iostream>
using namespace std;
class Animal {
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat : public Animal {
public:
void speak()
{
cout << "喵喵喵~~" << endl;
}
};
//执行说话的函数
//静态多态 - 地址早绑定,在编译阶段就确定了函数的地址
void doSpeak(Animal& animal){
animal.speak();
}
void test(){ Cat cat;doSpeak(cat); }
int main(){ test();return 0; }
class Animal{
public:
//虚函数 - 地址晚绑定
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
1.需要存在**继承**关系
2.**子类须<font color="Biue">重写</font>父类的<font color=MediumPurple>虚函数</font>**
+ **<font color="Blue">函数重写</font>**与<font color="Blue">**函数重载**</font>不同,后者是函数的类型相同(返回值同)、函数名相同,但函数的参数列表不同;前者则是函数返回类型、函数名、函数参数列表全都相同。
C++
class Animal{
public:
//虚函数 - 地址晚绑定
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat : public Animal {
public:
//子类重写父类的虚函数
void speak() --->virtual可写在子类上,也可不写
{
cout << "喵喵喵~~" << endl;
}
};
C++
//(Animal)父类的指针(或引用) 指向 子类对象
Animal& animal = cat;
void doSpeak(Animal& animal)
{
animal.speak();
}
doSpeak(cat);
多态调用核心:父类的指针(或引用)指向子类实例化出的对象
#include<iostream>
using namespace std;
class Base {
public:
//纯虚函数 - 只要类中有一个纯虚函数,那么这个类就被称为抽象类
virtual void func() = 0;
};
class Son : public Base {
public:
virtual void func()
{
cout << "纯虚函数 func() 的调用!" << endl;
}
};
void test(){
//利用多态的技术调用:父类的指针(或引用)指向子类对象
Base* base = new Son;
base->func();
}
int main(){test();return 0;}
#include<iostream>
using namespace std;
class Animal {
public:
void speak()
{
cout << "动物在说话" << endl;
}
};
class Cat : public Animal {
public:
void speak()
{
cout << "喵喵喵~~" << endl;
}
};
class Dog : public Animal {
public:
void speak()
{
cout << "汪汪汪~~" << endl;
}
};
void doSpeak(Animal& animal) {
animal.speak();
}
void test() {
Cat cat;
doSpeak(cat);
Dog dog;
doSpeak(dog);
}
void test01() {
cout << "sizeof(Animal) == " << sizeof(Animal) << endl;
}
int main() { test(); test01(); return 0; }
C++
class Animal {
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
c++
class Animal {
public:
virtual void speak()
{
cout << "动物在说话" << endl;
}
};
C++
class Cat : public Animal {
public:
//不存在重写时,请观察虚函数列表中的数据
};
C++
class Cat : public Animal {
public:
//子类对父类的虚函数进行重写
void speak()
{
cout << "喵喵喵~~" << endl;
}
};
#include<iostream>
using namespace std;
#include<string>
//普通写法:
class Calculator {
public:
int getResult(string oper){
if (oper == "+") return this->Num1 + this->Num2;
else if (oper == "-") return this->Num1 - this->Num2;
else if (oper == "*") return this->Num1 * this->Num2;
else if (oper == "/") return this->Num1 / this->Num2;
else if (oper == "%") return this->Num1 % this->Num2;
}
int Num1;//操作数1
int Num2;//操作数2
};
void test(){
Calculator c;
c.Num1 = 10;
c.Num2 = 20;
cout << c.Num1 << " + " << c.Num2 << " == " << c.getResult("+") << endl;
cout << c.Num1 << " - " << c.Num2 << " == " << c.getResult("-") << endl;
cout << c.Num1 << " * " << c.Num2 << " == " << c.getResult("*") << endl;
cout << c.Num1 << " * " << c.Num2 << " == " << c.getResult("/") << endl;
cout << c.Num1 << " * " << c.Num2 << " == " << c.getResult("%") << endl;
}
int main(){test();return 0;}
#include<iostream>
using namespace std;
#include<string>
//开创一个抽象类
class AbstractCalculator {
public:
//纯虚函数
virtual int getResult() = 0;
int Num1;
int Num2;
};
//加法计算器类
class AddCalculator : public AbstractCalculator {
public:
virtual int getResult()
{
return Num1 + Num2;
}
};
//减法计算器类
class SubCalculator : public AbstractCalculator {
public:
virtual int getResult()
{
return Num1 - Num2;
}
};
//乘法计算器类
class MulCalculator : public AbstractCalculator {
public:
virtual int getResult()
{
return Num1 * Num2;
}
};
void test01() {
//多态的使用条件 - 父类的指针或引用指向子类对象
//加法运算器
AbstractCalculator* abc = new AddCalculator;//在堆区创建一个AddCalculator类型的加法对象,并使用父类指针去指向这块区域
abc->Num1 = 10;
abc->Num2 = 20;
cout << abc->Num1 << " + " << abc->Num2 << " == " << abc->getResult() << endl;
//堆区数据手动开辟,手动释放
delete abc;
//减法运算器
abc = new SubCalculator;
abc->Num1 = 200;
abc->Num2 = 30;
cout << abc->Num1 << " - " << abc->Num2 << " == " << abc->getResult() << endl;
delete abc;
//乘法运算器
abc = new MulCalculator;
abc->Num1 = 40;
abc->Num2 = 79;
cout << abc->Num1 << " * " << abc->Num2 << " == " << abc->getResult() << endl;
delete abc;
}
int main(){test01();return 0;}
virtual 返回值类型 函数名 (参数列表) = 0;
抽象类的特点:
1.无法实例化对象
2.子类必须重写抽象类中的纯虚函数,否则也属于抽象类,且无法实例化对象
#include<iostream>
using namespace std;
class Base {
public:
//纯虚函数 - 只要类中有一个纯虚函数,那么这个类就被称为抽象类
virtual void func() = 0;
};
void test01()
{
//抽象类特点:1.无法实例化对象
Base b;//a.栈区上-->false
new Base;//b.堆区上-->false
}
C++
class Son : public Base {
public:
};
void test(){
Son s;
new Son;
}
#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 Coffe : 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* abc){
abc->MakeDrink();
delete abs;//释放堆区数据
}
void test() {
//调用制作功能
doWork(new Coffe);//使父类指针去指向子类对象
//doWork(new Tea);
}
int main(){test();return 0;}
注意:虚析构与纯虚析构之间无法共存
virtual ~类名(){}
virtual ~类名() = 0;
#include<iostream>
using namespace std;
class Animal {
public:
virtual void speak()
{
cout << "动物在说话!" << endl;
}
};
class Cat : public Animal {
public:
//在子类中重写父类虚函数
virtual void speak()
{
cout << "喵喵喵~~" << endl;
}
};
void test()
{
发生多态 - 地址晚绑定
Animal* animal = new Cat;
animal->speak();
delete animal;
}
int main(){test();return 0;}
#include<iostream>
using namespace std;
#include<string>
class Animal {
public:
Animal()
{
cout << "Animal 的构造函数调用!" << endl;
}
~Animal()
{
cout << "Animal 的析构函数调用!" << endl;
}
virtual void speak()
{
cout << "动物在说话!" << endl;
}
};
class Cat : public Animal {
public:
//Cat构造函数
Cat(string name)//在创建子类构造/析构函数之前,要先有父类的构造/析构,先走爹再走儿子
{
cout << "Cat 的构造函数调用!" << endl;
//将接收的name创建到堆区,并使用成员对象对其进行维护
m_Name = new string(name);
}
//在子类中重写父类虚函数
virtual void speak()
{
cout << *m_Name << "小猫在:喵喵喵~~" << endl;
}
//释放堆区数据
~Cat()
{
if (m_Name != NULL) {
cout << "Cat 析构函数调用!" << endl;
delete m_Name;
m_Name = NULL;
}
}
string* m_Name;//使成员对象,被创建在堆区
};
void test(){
Animal* animal = new Cat("啦啦啦");
animal->speak();
delete animal;
}
int main(){test();return 0;}
由代码的输出结果,可知Cat的析构函数被缺失掉了
产生原因:
C++
void test(){
Animal* animal = new Cat("啦啦啦");
animal->speak();
//父类指针在进行析构的时候,不会调用子类中的析构函数,这导致子类如果存在堆区的属性(或数据),就会出现内存泄露的情况
delete animal;
}
C++
virtual ~Animal()
{
cout << "Animal 的析构函数调用!" << endl;
}
父类指针无法释放子类对象
的问题,但要注意虚析构与纯虚析构**之间无法共存。 C++
virtual ~Animal() = 0;
无法解析的外部命令
,一般是在链接阶段所出现的错误,因为当我们只写virtual ~Animal() = 0;
,这其实只是一个声明,而并没有任何代码的实现
C++
class Animal {
public:
Animal()
{
cout << "Animal 的构造函数调用!" << endl;
}
//类内声明纯虚析构
virtual ~Animal() = 0;//纯虚析构
virtual void speak()
{
cout << "动物在说话!" << endl;
}
};
//类外实现纯虚析构
Animal::~Animal()
{
cout << "Animal 的纯虚析构函数调用!" << endl;
}
必须
执行我们子类当中的析构代码,但使用多态,我们是无法执行子类的析构函数的 —— 父类指针无法释放子类对象
总结:
1.虚/纯虚析构,是用来解决父类指针无法释放子类对象
的问题
2.如果子类中没有堆区数据,可以不写虚析构/纯虚析构函数>
3.拥有纯虚析构>的类也属于抽象类
#include<iostream>
using namespace std;
//1.抽象不同的零件类
//抽象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* vdcd, Memory* memroycard)
{
this->cpu = cpu;
this->vdcd = vdcd;
this->memroycard = memroycard;
}
//提供运作的函数
void doWork()
{
//使零件工作起来,调用接口
this->cpu->calculate();
this->vdcd->display();
this->memroycard->storage();
}
//提供析构函数,将三个电脑零件(堆区中的数据)释放掉
~Computer()
{
if (this->cpu != NULL)
{
delete this->cpu;
this->cpu = NULL;
}
if (this->vdcd != NULL)
{
delete this->vdcd;
this->vdcd = NULL;
}
if (this->memroycard != NULL)
{
delete this->memroycard;
this->memroycard = NULL;
}
}
private:
Cpu* cpu;//CPU零件指针
VideoCard* vdcd;//显卡零件指针
Memory* memroycard;//内存条零件指针
};
//实现具体的厂商 - Inter
class InterCpu : public Cpu {
public:
//子类重写父类中的纯虚函数
virtual void calculate()
{
cout << "Inter 的CPU 开始计算了!" << endl;
}
};
class InterVideoCard : 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 的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* INcpu = new InterCpu;
VideoCard* INvdcd = new InterVideoCard;
Memory* INmemory = new InterMemory;
//创建第一台电脑
Computer* computer1 = new Computer(INcpu, INvdcd, INmemory);
computer1->doWork();
delete computer1;
/* -----> 可以提供析构函数,将三个在堆区开辟的数据释放
delete INcpu;
delete INvdcd;
delete INmemory;
*/
cout << "--------------------------" << endl;
}
void test02()
{
Cpu* Levcpu = new LenovoCpu;
VideoCard* Levvc = new LenovoVideoCard;
Memory* Levmemory = new LenovoMemory;
//创建第二台电脑
Computer* computer2 = new Computer(Levcpu, Levvc, Levmemory);
computer2->doWork();
delete computer2;
}
int main(){test01();test02();return 0;}
文章来源: https://blog.csdn.net/2401_87692970/article/details/146429243
版权声明: 本文为博主原创文章,遵循CC 4.0 BY-SA 知识共享协议,转载请附上原文出处链接和本声明。