一,C++多态性概述
多态是指同样的消息被不同类型的对象接受时导致不同的行为。所谓消息是指对类的成员函数的调用,不同的行为是指不同的实现,也就调用不同的函数。换言之,多态指的就是用同样的接口访问功能不同的函数,从而实现“一个接口,多种方法”。
二,多态性分类
面向对象的多态性可以分为4类:重载多态,强制多态,包含多态,参数多态。前面两种统称专用多态,后面两种统称通用多态。
三,各种多态举例说明
1,重载多态:
重载多态包括前面学过的普通函数及类的成员函数的重载还有运算符的重载。
普通函数重载举例:
int add(int x, int y) { return x + y; } double add(double x, double y) { return x + y; } float add(float x, float y) { return x + y; }
类的成员函数相当于函数在类的内部实现重载,在这儿就不详细说明了,跟普通函数重载大同小异。
下面重点介绍运算符号重载:
运算符重载是对已有的运算符赋予多重含义,使同一个运算符作用于不同类型的数据导致不同的行为。
运算符重载可以分为重载为成员函数以及重载为非成员函数两种。
重载为成员函数:
其一般语法形式为:
返回类型 operator 运算符(形参表)
{
函数体
}
例1:(单目运算符)实现复数类前置++,后置++运算符重载
#include<iostream> using namespace std; class Complex { public: Complex(double r = 0, double i = 0) :real(r), image(i) {} Complex& operator ++() { ++this->image; ++this->real; return (*this); };//前++ Complex operator ++(int) { Complex temp = *this; ++(*this);//调用前置++ return temp; };//后++ void diaplayComplex() const { cout << "(" << this->real << "," << this->image << ")" << endl; }; private: double real; double image; }; int main() { Complex c1(1, 2); Complex c3(1, 2); Complex c2; c2=c1++; c1.diaplayComplex(); c2.diaplayComplex(); c2=++c3; c3.diaplayComplex(); c2.diaplayComplex(); return 0; }
运行结果:
这里需要注意的是前置++,返回值时Complex&
表示返回一个可修改的左值,后置++返回的是一个右值Complex
,另外,前置++形参表()
,后置++形参表(int)
,只是对两种运算作区分。
例2:(双目运算符)重载运算符实现对复数的加法
#include"operator.h" #include <iostream> using namespace std; class Complex { public: Complex(double r = 0, double i = 0) :real(r), image(i) {} Complex operator +(const Complex &c) const; void diaplayComplex() const; private: double real; double image; }; Complex Complex::operator +(const Complex &c)const { return Complex::Complex(c.real + this->real, c.image + this->image); }; void Complex::diaplayComplex() const { cout << "(" << this->real << "," << this->image << ")" << endl; }; int main() { Complex c1(1,2); Complex c2(1, 2); Complex c3;//保存运算结果 Complex c4;//保存运算结果 c3 = c1.operator+(c2);//传统方法调用 c3.diaplayComplex(); c4 = c1 + c2;//易懂的方法调用 c4.diaplayComplex(); return 0; }
运行结果:
重载为非成员函数:
一般语法形式:
返回类型 operator 运算符(形参表)
{
函数体
}
例1:对类Point重载“++”(自增),"--"(自减)运算符,要求同时重载前缀和后缀的形式,重载为非成员函数。
//对类Point重载“++”(自增),"--"(自减)运算符,要求同时重载前缀和后缀的形式 #include "pch.h" #include <iostream> using namespace std; class Point { public: Point(int x=0, int y=0) :x(x), y(y) {} void showPoint(); //以非成员函数类型实现 friend Point& operator ++( Point& p); friend Point operator ++(Point& p, int); private: int x, y; }; void Point::showPoint() { cout << "(" << x << "," <<y<< ")" << endl; } Point& operator ++( Point &p) {//前置++ ++(p.x); ++(p.y); return p; }; Point operator ++(Point& p, int) {//后置++ Point t = p; ++p; return t; }; int main() { Point p1, p2, p3; p3 = p1++; p3.showPoint(); p1.showPoint(); cout << "------------------------------------------" << endl; p3 = ++p2; p3.showPoint(); p2.showPoint(); return 0; }
运行结果:
注意,重载为非成员函数时,需要声明为友元函数,这样才能访问类的私有数据成员,从而实现相应功能。
2,强制多态
是指讲一个变元的类型加以变化,以符合一个函数或者操作的要求,举一个简单例子就清楚啦。
int a=1; float b=2.4f; float re=a+b;
这里的加法运算符在进行浮点数和整形数相加时,首先进行类型强制转换,把整形数变为浮点数再相加的情况就是强制多态的实例。
3,包含多态
指的是类族中定义于不同类中的同名函数的多态的行为,主要是通过虚函数来实现。
那么什么是虚函数呢?
虚函数:
在类的成员函数前加virtual关键字。虚函数是实现包含多态的基础。这里需要说明的是当基类里有虚函数且派生类中重新声明了和基类虚函数相同的函数,那么派生类该函数也是虚函数,这个过程称为对基类虚函数进行重写,这对于实现包含多态有重要意义。
包含多态的条件:
基类中必须包含虚函数,并且派生类中一定要对基类中的虚函数进行重写。
通过基类对象的指针或者引用调用虚函数。
下面举个例子进行分析,看此段代码,实现了包含多态
//编写一个哺乳动物类Mammal,再由此派生出狗类Dog,Cat类,三者都声明speak()成员函数,该函数在基类中被声明为虚函数。 #include <iostream> #include<string > using namespace std; class Mammal { public: virtual void speak(); private: string name; }; class Dog :public Mammal{ public: virtual void speak(); private: int age; }; class Cat :public Mammal { public: virtual void speak(); private: int age; }; void fun(Mammal *m) {//通过传入不同对象的实参,可调用产生对应的成员函数,以实现多态的功能 m->speak(); } void Mammal::speak() { cout << "I don't know what to speak" << endl; }; void Dog::speak() { cout << "wang ~~~wang~~~ wang~~~" << endl; }; void Cat::speak() { cout << "miao ~~~miao~~~ miao~~~" << endl; }; int main() { Dog d; Cat c; //传入不同对象的参数,实现相对应的功能(多态) fun(&d); fun(&c); return 0; }
运行结果:
这里speak()
函数定义为virtual,然后通过
void fun(Mammal *m) {//通过传入不同对象的实参,可调用产生对应的成员函数,以实现多态的功能 m->speak(); }
实现多态,注意fun()
形式参数只能是基类对象指针或者引用。fun()
函数也可以这样写,用基类引用实现:
void fun(Mammal &m) {//通过传入不同对象的实参,可调用产生对应的成员函数,以实现多态的功能 m.speak(); }
纯虚函数与抽象类:
纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定义具体的操作内容,要求各派生类根据实际需要给出各自的定义。纯虚函数的声明格式为:
virtual 函数类型 函数名 (参数表)=0;
而抽象类就是指带有纯虚函数的类。
对上面的例子进行修改,用抽象类实现:
//编写一个哺乳动物类Mammal,再由此派生出狗类Dog,Cat类,三者都声明speak()成员函数,该函数在基类中被声明为虚函数。 #include <iostream> #include<string > using namespace std; class Mammal { public: virtual void speak()=0; private: string name; }; class Dog :public Mammal{ public: virtual void speak(); private: int age; }; class Cat :public Mammal { public: virtual void speak(); private: int age; }; void fun(Mammal &m) {//通过传入不同对象的实参,可调用产生对应的成员函数,以实现多态的功能 m.speak(); } void Dog::speak() { cout << "wang ~~~wang~~~ wang~~~" << endl; }; void Cat::speak() { cout << "miao ~~~miao~~~ miao~~~" << endl; }; int main() { Dog d; Cat c; //传入不同对象的参数,实现相对应的功能(多态) fun(d); fun(c); return 0; }
这里需要注意的是抽象类不能进行实例化,如:
就会报错:
4,参数多态
采用函数模板,它可以用来创建一个通用的函数,以支持多种不同形参,避免重载函数的函数体重复设计,通过给出不同的类型参数,使得一个结构有多种类型。以实现参数多态。
定义的一般形式:
template
函数返回值类型 函数名(参数表)
{
函数体
}
举例说明:下面是求绝对值得函数模板及其应用。
#include "pch.h" #include <iostream> using namespace std; template <typename T> T abs(T x) { return x < 0 ? -x : x; } int main() { int a = 1; double b = -1; cout << abs(a) << endl; cout << abs(b) << endl; return 0; }
运行结果:
四,总结
多态性可以分为4类:重载多态,强制多态,包含多态,参数多态。
对于C++的多态性,这是一项很灵活的技术,用法十分灵巧。
简单来说:多态性就是适当的使用接口函数,通过一个接口来使用多种方法,(相当于上级说一个命令,甲乙丙丁等人都做出反应,一个命令,产生多个反应。