赞
踩
《c++ templates, chapter14》
术 语:
---通过继承实现的多态是 绑定的 和 动态的。
绑定指: 各个子类的接口需要与公共基类的虚函数相同。 有时,也把绑定这个概念称为入侵的或插入的。
动态指: 接口的绑定是在运行期完成的。用基类的指针去调用哪个子类的虚函数呢,运行时才确定;
---通过模板实现的多态是 非绑定的 和 静态的
非绑定指: 不需要基类提供公共的接口。
静态指: 接口的绑定是在编译期完成的,即在编译器确定调用的哪个类的哪个具体的函数。
在其他语言中,还可能会有其他组合存在,例如smalltalk提供了非绑定的动态多态。
-----优点和缺点:
c++动态多态的优点:
# 能够优雅地处理异类集合;
# 可执行代码通常比较小(因为对于静多态而言,为处理不同的类型必须生成多个不同的模板实例。例如,下面的myDraw(const GeoObj& obj)函数,对于动态多态而言,
只需要一份函数,但是对于静态多态而言,需要根据调用情况,生成myDraw_t<Line_t>, myDraw_t<Circle_t>等多份函数。)
c++静态多态的优点:
@ 代码效率较高,因为相比动态多态,其不存在通过指针的间接引用;
@ 具有更好的类型安全性,因为静多态会对所有的绑定操作进行检查。
缺陷:使用静多态后,再也不能透明地处理异类的集合;所有的类型都必须在编译期间确定;
基类的指针指向子类对象,实现虚函数的动态绑定。
对于动态多态,相当引人注目的一个特点是处理异类容器的能力! 如下的drawElems函数。
- //base calss
- class GeoObj {
- public:
- virtual void draw() const = 0;
- virtual float centerX_of_gravity() const = 0;
-
- };
- class Circle :public GeoObj {
- public:
- virtual void draw() const override
- {
- cout << "draw Circle\n";
- }
- virtual float centerX_of_gravity() const override {
- cout << "Called Circle::centerX_of_gravity" << endl;
- return 0.f;
- }
- };
-
- class Line :public GeoObj {
- public:
- virtual void draw() const override
- {
- cout << "draw Line\n";
- }
- virtual float centerX_of_gravity() const override {
- cout << "Called Line::centerX_of_gravity" << endl;
- return 0.f;
- }
- };
客户端代码:
- void myDraw(const GeoObj& obj) {
- obj.draw();
- }
-
- float distanceOfX(const GeoObj& obj1, const GeoObj& obj2) {
- float disX = obj1.centerX_of_gravity() - obj2.centerX_of_gravity();
- return std::fabs(disX);
- }
-
- //处理异类集合
- void drawElems(const vector<GeoObj*>& elems) {
- for (const auto& it: elems) {
- it->draw();
- }
- }
- int main() {
- Line line;
- Circle c, c1, c2;
- myDraw(line);
- myDraw(c);
- distanceOfX(line, c1);
-
- vector<GeoObj*> elemsVec;
- elemsVec.push_back(&line);
- elemsVec.push_back(&c1);
- elemsVec.push_back(&c2);
- drawElems(elemsVec);
- return 0;
- }
模板也能用于实现多态,这种多态不依赖于基类的存在 (动态多态需要在基类中声明公共的函数接口)。
这种多态的“公共性”体现在各个不同的类都需要支持某些公共的函数接口。另外,各个类之间是相互独立的哦。
- //具体的几何类。没有派生自其它任何类
- class Circle_t {
- public:
- void draw() const
- {
- cout << "draw Circle\n";
- }
- float centerX_of_gravity() const {
- cout << "Called Circle_t::centerX_of_gravity" << endl;
- return 0.f;
- }
- };
-
- class Line_t {
- public:
- void draw() const
- {
- cout << "draw Line\n";
- }
- float centerX_of_gravity() const {
- cout << "Called Line_t::centerX_of_gravity" << endl;
- return 0.f;
- }
- };
-
- class Check_t {
- public:
- void drawError() const
- {
- cout << "draw Line\n";
- }
- };
客户端的使用:
- template <class T>
- void myDraw_t(const T& obj) {
- obj.draw();
- }
-
- template <class T1, typename T2>
- float distanceOfX_t(const T1& obj1, const T2& obj2) {
- float disX = obj1.centerX_of_gravity() - obj2.centerX_of_gravity();
- return std::fabs(disX);
- }
-
- //只能将同类对象放到一个容器中:
- template<class T>
- void drawElems_t(const vector<T*>& elems) {
- for (const auto& it : elems) {
- it->draw();
- }
- }
-
-
- int main() {
- Line_t line;
- Line_t line1;
- myDraw_t(line); //编译器检测到该行后,会生成一个函数实例myDraw_t<Line_t>
-
- Circle_t c1;
- Circle_t c2;
- myDraw_t(c1); //编译器检测到该行后,会生成一个函数实例myDraw_t<Circle_t>
-
- distanceOfX_t(line,c1);//编译器检测到该行后,会生成一个函数实例distanceOfX_t<Line_t, Circle_t>
-
- vector<Line_t*> vect;
- vect.push_back(&line);
- vect.push_back(&line1);
- //vect.push_back(&c1); 不能酱Circle_t的对象放进去哦
- drawElems_t(vect);
-
- //Check_t checkObj;
- //myDraw_t(checkObj);//编译期间就可以检查出draw函数不是Check_t类的成员函数。
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。