一般,使用虚函数和继承实现的是动多态,即在运行期间确定调用者的类型。使用模板,可以实现静多态,在编译期间确定调用者的类型。
例如我们要对某一类对象进行统一处理,使用虚函数可以这样实现:
class BaseType
{
public:
virtual void action1(){...}
virtual void action2(){...}
}
class SubType1 : BaseType
{
public:
virtual void action1(){...}
virtual void action2(){...}
}
class SubType2 : BaseType
{
public:
virtual void action1(){...}
virtual void action2(){...}
}
// 统一处理
void DoAction1(BaseType const& type)
{
type.action1();
}
void DoAction2(BaseType* type)
{
type->action2();
}
// 可以处理异类集合
void DoActions(std::vector<BaseType*> list)
{
...
}
如果使用模板来实现,就会变成这样
class SubType1
{
public:
void action1(){...}
void action2(){...}
}
class SubType2
{
public:
void action1(){...}
void action2(){...}
}
// 统一处理
template<typename BaseType>
void DoAction1(BaseType const& type)
{
type.action1();
}
template<typename BaseType>
void DoAction2(BaseType* type)
{
type->action2();
}
// 不可以处理异类集合,因为要在编译期间确定,vector只能为一个类型的集合
template<typename BaseType>
void DoActions(std::vector<BaseType*> list) // 处理异类集合会报错
{
...
}
动多态和静多态两者的优点
动多态:
- 可以处理异类集合
- 生成的代码比较小,只需要一个多态函数,而静多态会生成多个实例化函数
静多态:
- 不需要和公共基类绑定,可以自由实现处理类型
- 代码运行效率更高,直接调用函数,虚函数间接调用;比虚函数拥有更多内联的机会
使用模板实现Bridge Pattern
用一个指针引用具体的实现,然后把所有的调用都委托给这个(包含这个指针)的类。
使用多态实现:
// 实现的接口基类
class Implementation
{
virtual operationA() = 0;
virtual operationB() = 0;
virtual operationC() = 0;
}
// 实现A
class ImplementationA : Implementation
{
virtual operationA(){...}
virtual operationB(){...}
virtual operationC(){...}
}
// 实现B
class ImplementationB : Implementation
{
virtual operationA(){...}
virtual operationB(){...}
virtual operationC(){...}
}
class Bridge
{
public:
// 通过将body指向不同的实现类来调用不同的实现
Implementation* body;
void operationA()
{
body->operationA();
}
void operationB()
{
body->operationB();
}
}
使用模板实现,即使用静多态:
// 实现A
class ImplementationA : Implementation
{
virtual operationA(){...}
virtual operationB(){...}
virtual operationC(){...}
}
// 实现B
class ImplementationB : Implementation
{
virtual operationA(){...}
virtual operationB(){...}
virtual operationC(){...}
}
template<typename Implementation>
class Bridge
{
public:
// 使用不同的类型来生成不同实现的实例化类
Implementation* body;
void operationA()
{
body->operationA();
}
void operationB()
{
body->operationB();
}
}
使用模板实现桥接模式的一个例子就是C++STL的迭代器,通过迭代器间接执行元素的操作。在容器扩容的时候,有时会重新申请一块内存,并将原来的数据转移过去,如果外面有指针指向容器内的元素,那么这个指针就会失效,如果是指向迭代器,那么就不会有问题。
template<typename T>
class Iterator
{
private:
T value;
public:
T operator+(T const& right){...}
...
}