基本介紹
- 中文名:靜多態
- 外文名:Static Polymorphism
概念,具體分類,表現形式,過程化編程,面向對象編程,泛型編程,靜多態動多態,
概念
其中靜多態就是綁定發生在編譯期(compile-time),此種綁定稱為靜態綁定static-binding);而動多態就是綁定發生在運行期(run-time),此種綁定稱為動態綁定(dynamic-binding)。
具體分類
1)非參數化多態(Ad-hoc polymorphism):
a)函式重載(Function Overloading)
b)運算符重載(Operator Overloading)
2)參數化多態(Parametric polymorphism)
c)模板(Template)
template<typename T>
T max(const T& lhs, const T& rhs)
{
return lhs > rhs ? lhs : rhs;
}
template<typename T>
T max(const T& fst, const T& sec, const T& thd)
{
return max(max(fst, sec), thd);
}
使用:
max(1, 3, 5);
max(2.4, 4.2);
表現形式
不同編程範例中的表現形式
註:由於C++同時支持下面要提到的三種編程範例(Programming Paradigm) ,所以就用C++語言為例來說明
過程化編程
C++中對靜多態的支持方式有:全局函式重載和運算符重載。
全局函式重載代碼:
1)參數個數不同而參數類型相同(對應位置):
void defParamNum(int paramFst);
void defParamNum(int paramFst, double paramSec);
2)參數個數相同而參數類型不同:
void defParamType (int paramFst, double paramSec);
void defParamType (double paramFst, int paramSec);
3)參數個數和參數類型都不相同:
void defBoth(int paramFst);
void defBoth(double paramFst, int paramSec);
運算符重載代碼:
其實運算符重載也是一種函式重載。其中多了一些限制,比如一元運算符、二元運算符所要求的參數個數,還有運算符重載的元型(Prototype)都有明確的規定,再就是一些像C語言等不支持運算符重載,所以這裡單獨列出來。
一元運算符重載:(負值運算符 operator -)
Complex operator – (const Complex& elem)
{
// 複數temp的值為0 + 0i
Complex temp;
// 將temp的實部設為elem實部負數
temp.setReal(-elem.getReal());
// 將temp的虛部設為elem虛部的負數
temp.setImage(-elem.getImage());
// 返回temp複數,此時temp就是elem對應的負數了
return temp;
}
二元運算符重載:(加法運算符 operator +)
Complex operator + (const Complex& lhs, const Complex& rhs)
{
// 複數temp的值為0 + 0i
Complex temp;
// 將temp的實部設為lhs和rhs實部的和
temp.setReal(lsh.getReal() + rhs.getReal());
// 將temp的虛部設為lhs和rhs虛部的和
temp.setImage(lsh.getImage() + rhs.getImage());
// 返回temp複數,此時的temp就是lhs和rhs的和
return temp;
}
面向對象編程
class Complex {
public:
// 構造函式重載:
Complex() : m_real(0), m_image(0) { };
Complex(double real, double image) : m_real(real), m_image(image) { };
// 靜態成員函式重載:不恰當的例子
staticvoid staticFunc()
{
std::cout << "staticFunc()" << std::endl;
}
staticvoid staticFunc(int oneParam)
{
std::cout << "staticFunc(int oneParam)" << std::endl;
}
// 虛函式重載:不恰當的例子
virtualvoid virtualFunc()
{
std::cout << "virtualFunc()" << std::endl;
}
virtualvoid virtualFunc(int oneParam)
{
std::cout << "virtualFunc(int oneParam)" << std::endl;
}
friendvoid friendFunc();
friendvoid friendFunc(int oneParam);
// 運算符重載:Comple + Comple
// Complex + Complex成員版本:允許一個complex對象和另一個Complex對象相加
Complex operator + (const Complex& elem)
{
return Complex(m_real + elem.m_real, m_image + elem.m_image);
}
// Complex + double成員版本:允許一個complex對象和另一個double對象相加
// 只能是Complex + double,不能是double + Complex
Complex operator + (double elem)
{
return Complex(m_real + elem, m_image);
}
// Complex + Complex友元版本:允許一個complex對象和另一個Complex對象相加
friend Complex operator + (const Complex& lsh, const Complex& rhs)
{
return Complex(lsh.m_real + rhs.m_real, lsh.m_image + rhs.m_image);
}
// Complex + double友元版本:允許一個complex對象和另一個double對象相加
// 只能是Complex + double,不能是double + Complex
friend Complex operator + (const Complex& lsh, double rhs)
{
return Complex(lsh.m_real + rhs, lsh.m_image);
}
// double + Complex友元版本:允許一個double對象和另一個Complex對象相加
//只能是double + Complex,不能是Complex + double
//和上面的Complex + double友元版本相輔相成
friend Complex operator + (double lhs, const Complex& rhs)
{
return Complex(lhs + rhs.m_real, rhs.m_image);
}
private:
double m_real;
double m_image;
};
void friendFunc()
{
std::cout << "virtualFunc()" << std::endl;
}
void friendFunc(int oneParam)
{
std::cout << "virtualFunc(int oneParam)" << std::endl;
}
註:見Complex類定義中的運算符重載部分!
泛型編程
在C++中,泛型編程(Generic Programming) 是通關過模板來實現的,然而模板不是與上述兩種編程範例有所不同,它必須依附於上述的某種範例,在某範例的基礎上來實現,就像面向對象和過程化編程的關係一樣。下面就是模板分類:
按泛化對象可分為:
1)類型泛化(Type):
template <typename T>
class List {
// ...
};
2)數值泛化(Value):
template <unsigned Num>
class Bit {
// ...
};
Bit<3> bit3; // bit3是長度為3位的位對象
template <typename T, unsigned Num>
class Array {
// ...
};
按泛化的載體可分為:
函式模板:
template <typename>
void functionGeneric()
{
// ...
}
類模板:
template <typename>
class classGeneric {
// ...
};
靜多態動多態
優缺點比較
靜多態是以犧牲靈活性而獲得運行速度的一種做法;而動多態則恰恰相反,它是以犧牲運行速度而獲取靈活性的做法。當然這么說是不全面的,看看下面這個特殊的套用:
使用靜多態來實現動多態
這是一種在模板元編程(Template Metaprogramming)中常見的標準編程技巧。在C++中,可以藉助模板來實現面向對象語言所支持動多態相似的功能特性(C++中指的就是的virtual 函式)。
下面是C++本身所支持多態形式:(virtual版)
#include <iostream>
class Base {
public:
virtual void method() = 0;
virtual ~Base() { }
};
class Derived : public Base {
public:
virtual void method()
{
std::cout << "Derived" << std::endl;
}
};
class Derived2 : public Base {
public:
virtual void method()
{
std::cout << "Derived2" << std::endl;
}
};
int main()
{ Base *pBase = new Derived;
pBase->method(); // 輸出:"Derived"
delete pBase;
Base *pBase2 = new Derived2;
pBase2->method(); // 輸出:"Derived2"
delete pBase2;
return 0;
}
註:C++本身是藉助virtual關鍵字來實現多態的(dynamic polymorphism),而通常編譯器是藉助virtual look-up tables(虛函式表)來決定該調用那個版本的函式,當然這一過程發生在運行期。
下面是使用CRTP(Curiously Recurring Template Pattern)來實現多與上面對應功能的靜多態代碼:
#include <iostream>
template <class Derived>
class Base {
public:
void method()
{
// ...
static_cast<Derived*>(this)->implementation();
// ...
}
};
class Derived : private Base<Derived> {
public:
void implementation()
{
std::cout << "Derived" << std::endl;
}
};
class Derived2 : private Base<Derived2> {
public:
void implementation()
{
std::cout << "Derived2" << std::endl;
}
};
int main()
{
Base<Derived> *pBase = new Base<Derived>();
pBase->method(); // 輸出:"Derived"
delete pBase;
Base<Derived2> *pBase2 = new Base<Derived2>();
pBase2->method(); // 輸出:"Derived2"
delete pBase2;
return 0;
}