《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; i draw(); // 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)对于只提供部分接口的具体类型,如果在应用程序中只是使用这一部分接口,那么也可以使用该具体类型,而不必在乎该类型是否提供其他部分的接口。 与动多态相比,静多态具有更好的类型安全性,因为静多态在编译期会对所有的绑定操作进行检查。

猜你喜欢

转载自www.cnblogs.com/snake-fly/p/13180177.html