一,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++的多態性,這是一項很靈活的技術,用法十分靈巧。
簡單來說:多態性就是適當的使用接口函數,通過一個接口來使用多種方法,(相當於上級說一個命令,甲乙丙丁等人都做出反應,一個命令,產生多個反應。