多态概述
一种对象为了接口重用而呈现的多重形态。
多态分类
多态分为两类:
- 静态多态:函数重载、运算符重载和模板
- 动态多态:派生类和虚函数
静态多态
函数重载
概念:函数名相同,形参数量、类型、顺序不同,返回值可同可不同
作用:接口重用,避免名字污染,提高可读性。
注意:形参无法通过const区分开,比如int max(int a)和int max(const int a)是一样的;而指针和引用可以通过const区分开,int max(int &a)和int max(const int &a)是不一样的。
底层实现:C语言中没有函数重载,因为编译器在编译的时候只会在函数名前加"_",所以两个函数名相同,编译出错。
在C++中,虽然函数名相同,但是它们在符号表中生成的名字不同,会同时加入返回值类型和形参类型来命名,所以编译可以通过。
运算符重载
概念:对已有的运算符进行重新定义,赋予其另一种功能,以适应不同的数据类型。
运算符重载的实质是函数重载,可以重载为普通函数,也可以重载为类成员函数。运算符重载的基本形式如下:
返回值类型 operator运算符(形参表)
{ }
例子:
#include <iostream>
using namespace std;
class Complex
{
public:
Complex(double real = 0.0, double imag = 0):m_real(real), m_imag(imag) { }
// 重载-号的类成员函数
Complex operator-(const Complex &c)
{
return Complex(m_real-c.m_real, m_image-c.image);
}
void PrintComplex()
{
cout<<m_real<<","<<m_image<<endl;
}
//重载运算符+号的普通函数,定义为友元函数
friend Complex operator+(const Complex &a, const Complex &b);
private:
double m_real;
double m_imag;
};
Complex operator+(const Complex &a, const Complex &b)
{
return Complex(a.m_real+b.m_real, a.m_image+b.m_image);
}
int main()
{
Complex a(1,1);
Complex b(2,2);
Complex c;
c = a + b; //等价于c=Complex operator+(a,b)
c.PrintComplex();
c = a - b; //等价于c=a.operator-(b)
c.PrintComplex();
return 0;
}
输出结果:
3,3
-1,-1
注意:
- 重载-号和+号的运算符函数返回类型是Complex而不是Complex&
因为函数执行之后,需要返回一个新的对象给到左值 - 重载-号和+号运算符函数参数表是const Complex &a,是常引用,而不是Complex a
因为如果是Complex a,在入参时就会调用默认的赋值(拷贝)构造函数,产生了一个临时变量,这会增大开销,所以采用引用。采用const,防止引用对象被修改
模板(泛型)
函数模板
概念:函数模板就是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为模板。
编译器对函数模板进行二次编译:在声明的地方对模板代码本身进行编译;在调用的地方对参数替换后的代码进行编译。
用法:
#include <iostream>
using namespace std;
template <typename type1, typename type1>
type Max(type1 a, type2 b)
{
return a>b?a:b;
}
void main()
cout << Max(5.5, 'a') << endl;
参数匹配优先级:
在有多个函数和函数模板名字相同的情况下,一条函数调用语句,到底应该被匹配成哪个函数或对哪个模板的调用呢?C++编译器遵循以下规则:
- 先找参数完全匹配的普通函数
- 再找参数完全匹配的模板函数
- 然后找实参经过自动类型转换后能够匹配的普通函数
- 上面的都找不到则报错
函数模板的局限性:模板并不是真正通用的代码,对于一些自定义的数据,模板有时候不能实现效果。可以通过具体化实现对自定义数据类型进行操作
例如:
template<class T>
bool myCompare(T &a, T &b)
{
if(a == b)
return true;
else
return false;
}
template<> myCompare<Person>(Person &a, Person &b)
{
if(a.m_name == b.m_name && a.m_age == b.m_age)
return true;
return false;
}
类模板
类模板概念:用于解决多个功能相同、数据类型不同的类需要重复定义的问题。
基本用法:
类模板的定义形式:
template <class 类型参数1, class 类型参数2, …>
class 类模板
{
成员变量和成员函数
};
用类模板定义对象:
类模板<真实类型参数表> 对象名(构造函数实参表);
比如:
template <typename T1, typename T2>
class Student
{
private:
T1 m_name;
T2 m_score;
public:
Student() = default;
Student(T1 name, T2 score):m_name(name), m_score(score) {}
Student(const Student<T1,T2> &s)
{
m_name = s.m_name;
m_score = s.m_score;
}
void print_info();
}
template<typename T1, typename T2>
void Student::print_info()
{
cout << m_name << endl;
cout << m_score << endl;
}
void main()
{
Student<string, double> s;
}
动态多态
即虚函数,具体详见C++之继承