欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 类和对象-多态-C++

类和对象-多态-C++

2025/3/10 10:39:42 来源:https://blog.csdn.net/2401_84315007/article/details/146024254  浏览:    关键词:类和对象-多态-C++

多态是C++面向对象的三大特征之一

1.分类

静态多态:函数重载和运算符重载属于静态多态,服用函数名。

动态多态:派生类和虚函数实现运行时多态。

2.区别

静态多态的函数地址早绑定--编译阶段确定函数地址。

动态多态的函数地址晚绑定--运行阶段确定函数地址。

3.出现的问题

我们想要的效果是输出“猫说话”,实际输出“动物在说话”,因为C++中允许父子类之间的类型转换,而且地址早绑定,在编译阶段就已经确定。

#include<iostream>
using namespace std;
#include<string>
class animal
{
public:void speak(){cout << "动物在说话" << endl;}
};
class cat:public animal
{
public:void speak(){cout << "猫在说话" << endl;}
};
void fun(animal &a)
{a.speak();
}
int main()
{cat a;fun(a);return 0;
}

4.解决方法

使用动态多态

1.原因:因为动态多态是地址晚绑定,只有在运行阶段才会绑定。

2.方法:将animal中的speak函数变为虚函数

3.代码实现

#include<iostream>
using namespace std;
#include<string>
class animal
{
public:virtual void speak(){cout << "动物在说话" << endl;}
};
class cat:public animal
{
public:void speak(){cout << "猫在说话" << endl;}
};
void fun(animal &a)
{a.speak();
}
int main()
{cat a;fun(a);return 0;
}

这个是用引用实现的动态多态

5.动态多态满足条件

1.有继承关系

2.子类重写父类的虚函数(重写定义:函数返回值类型,函数名,参数列表要完全相同。)

6.动态多态使用场景

父类的指针引用执行子类对象

7.底层原理

就是指针介入,使后续可以更改了

8.案例一

1.题目

利用多态实现计算器

2.多态优点

如果想扩展新的内容,不需要修改源码,只需要添加新的代码就行,符合开闭原则,利于维护。

(开闭原则:对扩展进行开放,对修改进行关闭)

3.实现步骤

利用指针方法实现多态,上面的方法是利用引用实现多态。

4.代码实现

#include<iostream>
using namespace std;
#include<string>
class calculator
{
public:virtual int fun(){return 0;}int num1 = 10;int num2 = 10;
};
class jia:public calculator
{
public:int fun(){return num1 + num2;}
};
class jian :public calculator
{
public:int fun(){return num1 - num2;}
};
class cheng :public calculator
{
public:int fun(){return num1 * num2;}
};
void fun2()
{calculator* abc = new jia;abc->num1 = 10;abc->num2 = 10;cout << abc->num1 << "+" << abc->num2 << "=" << abc->fun() << endl;abc = new jian;abc->num1 = 10;abc->num2 = 10;cout << abc->num1 << "-" << abc->num2 << "=" << abc->fun() << endl;abc = new cheng;abc->num1 = 10;abc->num2 = 10;cout << abc->num1 << "*" << abc->num2 << "=" << abc->fun() << endl;
}
int main()
{calculator a;jia b;jian c;cheng d;fun2();return 0;
}

9.纯虚函数和抽象类

1.定义

在多态中,通常父类中的虚函数是毫无意义的,主要都是来调用子类重写的内容,因此可以将虚函数改为纯虚函数。(当类中有了抽象函数,这个类也叫做抽象类)

2.纯虚函数语法

virtual 返回值类型 函数名(参数列表)=0;

3.抽象类特点

1.无法实例化对象

2.子类必须重写抽象类。中的纯虚函数,否则也属于抽象类。

4.代码演示

#include<iostream>
using namespace std;
#include<string>
class calculator
{
public:virtual void fun() = 0;
};
class jia:public calculator
{
public:void fun(){cout << "子类调用" << endl;}
};
int main()
{jia b;calculator* abc = new jia;abc->fun();return 0;
}

5.案例二

1.题目

使用纯虚函数构造饮品

2.代码实现

#include<iostream>
using namespace std;
#include<string>
class abstractdrinking
{
public://煮水virtual void boil() = 0;//冲泡virtual void brew() = 0;//倒入杯中virtual void pourincup() = 0;//加入辅料virtual void putsth() = 0;//整体实现void makedrink(){boil();brew();pourincup();putsth();}
};
class tea:public abstractdrinking
{
public://煮水virtual void boil(){cout << "煮农夫山泉" << endl;}//冲泡virtual void brew() {cout << "放入茶叶" << endl;}//倒入杯中virtual void pourincup(){	cout << "入杯中" << endl;}//加入辅料virtual void putsth(){cout << "加蜂蜜" << endl;}
};
void gowork(abstractdrinking *abc)
{abc->makedrink();delete abc;//释放
}
void maketea()
{gowork(new tea);
}
int main()
{maketea();return 0;
}

10.虚析构和纯虚析构

1.作用

多态使用时,如果有子类开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码,将父类中的析构函数改为虚析构和纯虚析构。

2.无虚析构和纯析构版

#include<iostream>
using namespace std;
#include<string>
class animal
{
public:animal(){cout << "animal构造函数调用" << endl;}~animal(){cout << "animal析构函数调用" << endl;}virtual void speak() = 0;
};
class cat:public animal
{
public:cat(string name){cout << "cat构造函数调用" << endl;Name = new string(name);}~cat(){if (Name != NULL){cout << "cat析构函数调用" << endl;delete Name;Name = NULL;}}string* Name;void speak(){cout << *Name<<"cat在说话" << endl;}
};
void fun()
{animal* abc = new cat("tom");abc->speak();delete abc;
}
int main()
{fun();return 0;
}

问题:cat的析构函数未被调用,所以Name的堆区未被释放,导致内存泄漏。

3.虚析构版代码

#include<iostream>
using namespace std;
#include<string>
class animal
{
public:animal(){cout << "animal构造函数调用" << endl;}virtual ~animal(){cout << "animal析构函数调用" << endl;}virtual void speak() = 0;
};
class cat:public animal
{
public:cat(string name){cout << "cat构造函数调用" << endl;Name = new string(name);}~cat(){if (Name != NULL){cout << "cat析构函数调用" << endl;delete Name;Name = NULL;}}string* Name;void speak(){cout << *Name<<"cat在说话" << endl;}
};
void fun()
{animal* abc = new cat("tom");abc->speak();delete abc;
}
int main()
{fun();return 0;
}

4.纯虚析构版代码

#include<iostream>
using namespace std;
#include<string>
class animal
{
public:animal(){cout << "animal构造函数调用" << endl;}virtual ~animal() = 0;virtual void speak() = 0;
};
animal::~animal()
{cout << "animal析构函数调用" << endl;
}
class cat:public animal
{
public:cat(string name){cout << "cat构造函数调用" << endl;Name = new string(name);}~cat(){if (Name != NULL){cout << "cat析构函数调用" << endl;delete Name;Name = NULL;}}string* Name;void speak(){cout << *Name<<"cat在说话" << endl;}
};
void fun()
{animal* abc = new cat("tom");abc->speak();delete abc;
}
int main()
{fun();return 0;
}

注意:纯虚析构要有声明和实现两部分组成。

4.区别

虚析构和纯虚析构区别:如果是纯虚析构,该类属于抽象类,无法实例化对象。

5.注意

如果子类中没有堆区数据,可以不用写虚析构和纯虚析构

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词