1)非参数化多态(Ad-hoc polymorphism):
a) 函数重载 (Function Overloading)
b) 运算符重载 (Operator Overloading)
2)参数化多态(Parametric polymorphism)
c) 模板 (Template)
其实非参数化多态和参数化多态并不冲突,而且相辅相成,它们混合使用能够带来更大的灵活性, 函数模板 重载 就是很好的例子:
template
T max(const T& lhs, const T& rhs)
{
return lhs > rhs ? lhs : rhs;
}
template
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++中对静多态的支持方式有:全局函数重载和 运算符重载
全局函数重载代码:
一下代码中均不考虑函数的返回 类型 ,因为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;
}

静多态 面向对象编程

其实 面向对象编程 (Object-Oriented Programming)中也表现为 函数重载 和运算符重载。
函数重载: 成员函数 重载,静态成员函数(static)重载, 虚函数 重载, 友元 函数重载
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
class List {
// ...
};
List iList; // iList是能够存储int 类型 链表 对象
2) 数值 泛化(Value):
template
class Bit {
// ...
};
Bit<3> bit3; // bit3是长度为3位的位对象
3) 数值 类型 泛化(Type & Value):
template
class Array {
// ...
};
Array iArray3; // iArray3是能够存储3个int 类型 数组 对象
按泛化的载体可分为:
template
void functionGeneric()
{
// ...
}
template
class classGeneric {
// ...
};
优缺点比较
静多态是以牺牲灵活性而获得运行速度的一种做法;而动多态则恰恰相反,它是以牺牲运行速度而获取灵活性的做法。当然这么说是不全面的,看看下面这个特殊的应用:
使用静多态来实现动多态
这是一种在 模板元 编程(Template Metaprogramming)中常见的标准编程技巧。在C++中,可以借助 模板 来实现 面向对象语言 所支持动多态相似的功能特性(C++中指的就是的virtual 函数)。
下面是C++本身所支持多态形式:(virtual版)
#include
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
template
class Base {
public:
void method()
{
// ...
static_cast(this)->implementation();
// ...
}
};
class Derived : private Base {
public:
void implementation()
{
std::cout << "Derived" << std::endl;
}
};
class Derived2 : private Base {
public:
void implementation()
{
std::cout << "Derived2" << std::endl;
}
};
int main()
{
Base *pBase = new Base();
pBase->method(); // 输出:"Derived"
delete pBase;
Base *pBase2 = new Base();
pBase2->method(); // 输出:"Derived2"
delete pBase2;
return 0;
}
虽然使用这种方式实现的多态和 面向对象 中的多态从功能上说差不多相同,但是前者没有后者易用、易懂、和能力强大。虽然如此,CRTP作为一种 模板 设计模式还是很有用的,例如,Boost iterator library就是用了这种方法来实现。
其实在别的语言中也存在CRTP这种模式,如Java,Enum类被定义为Enum>,当然由于Java在 模板 方面的不足,作为Java语言的使用者,你是没法自己体验这样的用法(Java虽然支持模板特性,但是用户不能自己定义模板,只能使用库里边的 模板类 )。