1.什么是多态?
多态和封装继承作为c++面向对象的三个基本特征.封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。而多态则是为了实现另一个目的——接口重用!
2.实现多态的两种方法:覆盖(虚函数,接口)\重载
3.重载-----称为静态多态
什么是重载函数? C++允许在同一范围中声 明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数完成不同的功能。这就是重载函数。重载函数常用来实现功能类似而所处理的数据类型不同的问题。不能只有函数返回值类型不同。 举个简单的例子:
void max_two_nums(int a,int b){
cout<<res<<endl;
}
void max_two_nums(float a,float b){
cout<<max(a,b)<<endl;
}
int main(){
max_two_nums(1,4);\\4
max_two_nums(1.0f,4.3f);\\4.3
max_two_nums(1,4.3f);\\error
}
求两数当中最大的那个数,函数名称相同,说明函数的功能类似,但是由于第一个max_two_nums中参数为两个int型,第二个max_two_nums中参数为float,所以上述的两个函数就可以称为重载函数. 简单的说就是同一个函数通过形参的不同来完成相似的功能就是重载.
举个简单的例子: DVD盒子的功能是播放音视频,把它看做一个函数,一个DVD盒子可以有很多个光盘,那么不同的光碟就是不同的形式参数,根据实参(歌曲->光盘编号)选择哪个光盘进行播放. 例如有如下几个编号的光碟: 标号:歌曲 1. 稻香 2. 米香 3. 面香 4. 花香 5. 菜香 我根据稻香找到光盘标号为1,放入盒子中就能听到想听的歌曲了. 当然这个不是很严谨,因为重载函数DVD盒子不是一个.
静态多态是编译器在表一期间完成的,编译器会根据实参的类型,调用合适的函数,没有合适的函数调用时.返回错误提示. 如上面的实例中第三个就会提示error,为了改进可以在上面的函数中加上:
void max_two_nums(int a,float b){
cout<<max(a,b)<<endl;
}
4.虚函数-----动态多态:
虚函数与纯虚函数: 虚函数:某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。
纯虚函数:基类中有虚函数关键字virtual之后的函数=0,就是一个纯虚函数
虚函数与纯虚函数的区别:
- 定义一个函数为虚函数,不代表函数为不被实现的函数。
- 定义一个函数为虚函数是为了允许用基类的指针来调用子类的这个函数。
- 定义一个函数为纯虚函数,才代表函数没有被实现。
- 定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序必须实现这个函数。
什么意思呢? 就是说虚函数的设定就是为了派生类在继承的时候可以用指针方便的使用子类函数(这里的子类函数就是虚函数在派生类中对应的函数),而纯虚函数的诞生就是一个空的接线口,在派生类中必须重写实现。
不能被定义程序函数的函数: 友元函数 全局函数 静态成员函数:静态成员函数就是在声明时前面加了 static 关键字的成员函数,它没有this指针 构造函数:它会在每次创建类的新对象时执行。构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
一个简单的例子:
#include <iostream>
#include <map>
#include <string.h>
#include <string>
#include <cctype>
#include <stdio.h>
#include <algorithm>
using namespace std;
void Add(int left, int right)
{
cout<<"1 add =:"<<max(left,right)<<endl;
}
void Add(float left, float right)
{
cout<<"2 add =:"<<max(left,right)<<endl;
}
class Base{
public:
Base();
~Base();
static void f1(int a){
}
friend void printname(Base b);
string students(string name){
cout<<"Base students is:"<<name<<endl;
return name;
}
void class_nums(int n){
cout<<"Base class is:"<<n<<endl;
}
virtual void socre(double s){
cout<<"Base socre is:"<<s<<endl;
}
};
class Check:public Base{
string void students(string name){
cout<<"Check students name is:"<<name<<endl;
return name;
}
void class_nums(int n){
cout<<"Check students class is:"<<n<<endl;
}
virtual void socre(double s){
cout<<"Check socre is:"<<s<<endl;
}
};
void printname(Base b)
{
cout << "b's name : " << b.students("通南北") <<endl;
}
void test(Base& b){
b.students("通南北");
b.class_nums(1);
b.socre(60);
}
int main()
{
Base b;
Check c;
test(b);
test(c);
Add(10, 20);
Add(0.9f,20.0f);
return 0;
}
结果是 这里只在score成绩一个函数中加了virtual也就是只有成绩为虚函数,所以在主函数main中调用只有score使用了派生类中的函数. 也就是说使用虚函数再使用指针就可以实现多态; 回顾一下重点:
- 基类中必须包含虚函数,并且派生类中一定要对基类中的虚函数进行重写
- 通过基类对象的指针或者引用调用虚函数。
多态缺陷 ●降低了程序运行效率(多态需要去找虚表的地址) ●空间浪费
参考:C++ 之 多态(非常非常重要,重点在后面) C++封装、继承、多态
|