在面向对象的编程中,总是以显式接口和运行期多态解决问题,而在Temlplate和泛型编程中,主要是隐式接口和编译期多态。
1.显式接口
由函数的声明构成(函数名称、参数类型、返回类型),如:int fun(int x);看到函数声明我们就知道函数名称,返回类型,参数类型,这种是显示接口。面向对象的编程在类中声明函数,就是显示接口,每当我们调用了类的函数,我们就可以通过类中的声明了解到这个函数的样子,也就是函数在源码中明确可见。
2.运行期多态
在程序运行时决定哪一个virtual函数该被绑定,就是多态性,在运行时根据动态对象的类型选择函数。
如:
#include <iostream>
using namespace std;
class base
{
public:
virtual void fun()
{
cout << "base::fun" << endl;
}
};
class Derived :public base
{
public:
void fun()
{
cout << "Derived::fun" << endl;
}
};
int main()
{
base *b;
Derived d;
b = &d;
b->fun();
base a;
b = &a;
b->fun();
return 0;
}
一开始b的动态类型(指针所指的元素的类型)是Derived所以调用Derived::fun(),后来b的动态类型变为base,调用的是base::fun()
3.隐式接口
基于有效表达式
template<typename T>
void doProcessing(T& w)
{
if (w.size() > 10 && w != someNastyWidget)
{
T temp(w);
temp.normalize();
temp.swap(w);
}
}
我们可以根据函数中对w执行的操作判断出w需要支持的接口,也就是说我们根据表达式推断接口,这种就是隐式接口,是不明确的,对函数的要求是隐藏在表达式中的。
4.编译期多态
类似于决定那个重载函数被调用(发生在编译期)。比如写了一个比较大小的函数模板,数据类型为T,这个T就是在编译器确定具体的类型的,如果T是int,就调用int版本的比较函数,如果是double就调用double版本的,所以编译期多态就是决定那个重载函数被调用。
请记住:
1.classes和templates都支持接口和多态
2.对于classes而言接口是显示的,以函数声明为中心。多态则是virtual函数发生于运行期
3.对于template参数而言,接口是隐式的,奠基于有效表达式。多态则是通过template具现化和函数重载解析发生于编译期