《C++ Template》学习笔记--模板的多态威力
多态分为动多态和静多态
动多态在运行期处理,通过虚函数和继承来实现,设计思想主要在于:对于几个相关对象的类型,确定它们之间的一个共同功能集;然后在基类中,把这些共同的功能声明为多个虚函数接口。也就是说,利用一个指向基类(子对象)的指针或者引用来调用虚成员函数,实际上将调用(指针或者引用实际上代表的)具体类对象的相应成员。
对于动多态而言,最引人注目的特性或许是处理异类容器的能力,比如elem[i]->draw(),将会根据被迭代的类型,而调用不同的成员函数。
示例如下:
coord.hpp
#ifndef COORD_HPP
#define COORD_HPP
#include
class Coord {
private:
int x, y;
public:
Coord (int i1, int i2) : x(i1), y(i2) {
}
friend Coord operator- (Coord const& c1, Coord const& c2) {
return Coord(c1.x-c2.x, c1.y-c2.y);
}
Coord abs() {
return Coord(std::abs(x),std::abs(y));
}
};
#endif // COORD_HPP
dynahier.hpp
#include "coord.hpp"
#include
// common abstract base class GeoObj for geometric objects
class GeoObj {
public:
// draw geometric object:
virtual void draw() const = 0;
// return center of gravity of geometric object:
virtual Coord center_of_gravity() const = 0;
//...
virtual ~GeoObj() = default;
};
// concrete geometric object class Circle
// - derived from GeoObj
class Circle : public GeoObj {
public:
void draw() const override;
Coord center_of_gravity() const override;
//...
};
void Circle::draw() const
{
std::cout<<"Circle Draw."<
#include
// draw any GeoObj
void myDraw (GeoObj const& obj)
{
obj.draw(); // call draw() according to type of object
}
// compute distance of center of gravity between two GeoObjs
Coord distance (GeoObj const& x1, GeoObj const& x2)
{
Coord c = x1.center_of_gravity() - x2.center_of_gravity();
return c.abs(); // return coordinates as absolute values
}
// draw heterogeneous collection of GeoObjs
void drawElems (std::vector const& elems)
{
for (std::string::size_type i=0; idraw(); // call draw() according to type of element
}
}
int main()
{
Line l;
Circle c, c1, c2;
myDraw(l); // myDraw(GeoObj\&) => Line::draw()
myDraw(c); // myDraw(GeoObj\&) => Circle::draw()
distance(c1,c2); // distance(GeoObj\&,GeoObj\&)
distance(l,c); // distance(GeoObj\&,GeoObj\&)
std::vector coll; // heterogeneous collection
coll.push_back(&l); // insert line
coll.push_back(&c); // insert circle
drawElems(coll); // draw different kinds of GeoObjs
}
使用如下命令编译:
g++ -g -o dynapoly dynapoly.cpp -std=c++11
运行结果如下:
./dynapoly
Line Draw.
Circle Draw.
Circle center_of_gravity.
Circle center_of_gravity.
Circle center_of_gravity.
Line center_of_gravity.
Line Draw.
Circle Draw.
静多态在编译期处理,通过模板来实现。这种多态不依赖于在基类中包含公共行为的因素,具体类之间的定义是相互独立的,但都必须包含公共语法的操作。
示例如下:
coord.hpp
#ifndef COORD_HPP
#define COORD_HPP
#include
class Coord {
private:
int x, y;
public:
Coord (int i1, int i2) : x(i1), y(i2) {
}
friend Coord operator- (Coord const& c1, Coord const& c2) {
return Coord(c1.x-c2.x, c1.y-c2.y);
}
Coord abs() {
return Coord(std::abs(x),std::abs(y));
}
};
#endif // COORD_HPP
statichier.hpp
#include "coord.hpp"
#include
// concrete geometric object class Circle
// - \bfseries not derived from any class
class Circle {
public:
void draw() const;
Coord center_of_gravity() const;
//...
};
void Circle::draw() const
{
std::cout<<"Circle draw."<
// draw any GeoObj
template
void myDraw (GeoObj const& obj)
{
obj.draw(); // call draw() according to type of object
}
// compute distance of center of gravity between two GeoObjs
template
Coord distance (GeoObj1 const& x1, GeoObj2 const& x2)
{
Coord c = x1.center_of_gravity() - x2.center_of_gravity();
return c.abs(); // return coordinates as absolute values
}
// draw homogeneous collection of GeoObjs
template
void drawElems (std::vector const& elems)
{
for (unsigned i=0; i(GeoObj\&) => Line::draw()
myDraw(c); // myDraw(GeoObj\&) => Circle::draw()
distance(c1,c2); // distance(GeoObj1\&,GeoObj2\&)
distance(l,c); // distance(GeoObj1\&,GeoObj2\&)
// std::vector coll; // ERROR: no heterogeneous collection possible
std::vector coll; // OK: homogeneous collection possible
coll.push_back(l); // insert line
drawElems(coll); // draw all lines
}
编译命令如下:
g++ -g -o staticpoly staticpoly.cpp -std=c++11
执行结果如下:
# ./staticpoly
Circle draw.
Circle draw.
Circle center_of_gravity.
Circle center_of_gravity.
Circle center_of_gravity.
Line center_of_gravity.
Circle draw.
不再能透明的处理异类集合,这也是静态多态的静态特性所强加的约束:所有的类型必须能在编译期确定。
通过继承实现的多态是绑定的和动态的。
通过模板实现的多态是非绑定的和静态的。
动多态的优点:
(1)能优雅的处理异类集合
(2)可执行程序的大小一般较小(因为只需要一个静态函数,但对于静多态而言,为了处理不同的类型,必须生成多个不同的模板实例)
(3)可以对代码进行安全编译,因此并不需要发布实现源码。
静多态的优点:
(1)可以很容易的实现内建类型的集合,并不需要通过公共基类来表达接口的共同性
(2)所生成的代码效率通常都比较高(因为并不存在通过指针的间接调用,而且,可以进行演绎的非虚拟函数具有更多的内联机会)
(3)对于只提供部分接口的具体类型,如果在应用程序中只是使用这一部分接口,那么也可以使用该具体类型,而不必在乎该类型是否提供其他部分的接口。
与动多态相比,静多态具有更好的类型安全性,因为静多态在编译期会对所有的绑定操作进行检查。