C++中的静态多态和动态多态

发表于:2014-5-07 10:01

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:lizhenghn    来源:51Testing软件测试网采编

分享:
  动态多态本质上就是面向对象设计中的继承、多态的概念。动态多态中的接口是显式接口(虚函数),比如,
1 void DoSomething(Widget& w)
2 {
3     if( w.size() > 0 && w != someNastyWidget)
4     {
5         Widget temp(w);
6         temp.normalize();
7         temp.swap(w);
8     }
9 }
  对于上面的代码,这要求:
  由于w的类型被声明为Widget,所以w必须支持Widget接口,且通常可以在源码中找出这些接口(比如Widget.h),因此这些接口也就是显示接口;
  Widget可能只是一个基类,他有子类,也就是说Widget的接口有可能是虚函数(比如上面的normalize),此时对接口的调用就表现出了运行时多态;
  什么是静态多态?
  静态多态的设计思想:对于相关的对象类型,直接实现它们各自的定义,不需要共有基类,甚至可以没有任何关系。只需要各个具体类的实现中要求相同的接口声明,这里的接口称之为隐式接口。客户端把操作这些对象的函数定义为模板,当需要操作什么类型的对象时,直接对模板指定该类型实参即可(或通过实参演绎获得)。
  相对于面向对象编程中,以显式接口和运行期多态(虚函数)实现动态多态,在模板编程及泛型编程中,是以隐式接口和编译器多态来实现静态多态。
  看代码:
1 namespace StaticPoly
2 {
3     class Line
4     {
5     public:
6         void Draw()const{    std::cout << "Line Draw()\n";    }
7     };
8
9     class Circle
10     {
11     public:
12         void Draw(const char* name=NULL)const{    std::cout << "Circle Draw()\n";    }
13     };
14
15     class Rectangle
16     {
17     public:
18         void Draw(int i = 0)const{    std::cout << "Rectangle Draw()\n";    }
19     };
20
21     template<typename Geometry>
22     void DrawGeometry(const Geometry& geo)
23     {
24         geo.Draw();
25     }
26
27     template<typename Geometry>
28     void DrawGeometry(std::vector<Geometry> vecGeo)
29     {
30         const size_t size = vecGeo.size();
31         for(size_t i = 0; i < size; ++i)
32             vecGeo[i].Draw();
33     }
34 }
35
36 void test_static_polymorphism()
37 {
38     StaticPoly::Line line;
39     StaticPoly::Circle circle;
40     StaticPoly::Rectangle rect;
41     StaticPoly::DrawGeometry(circle);
42
43     std::vector<StaticPoly::Line> vecLines;
44     StaticPoly::Line line2;
45     StaticPoly::Line line3;
46     vecLines.push_back(line);
47     vecLines.push_back(line2);
48     vecLines.push_back(line3);
49     //vecLines.push_back(&circle); //编译错误,已不再能够处理异质对象
50     //vecLines.push_back(&rect);    //编译错误,已不再能够处理异质对象
51     StaticPoly::DrawGeometry(vecLines);
52
53     std::vector<StaticPoly::Circle> vecCircles;
54     vecCircles.push_back(circle);
55     StaticPoly::DrawGeometry(circle);
56 }
  静态多态本质上就是模板的具现化。静态多态中的接口调用也叫做隐式接口,相对于显示接口由函数的签名式(也就是函数名称、参数类型、返回类型)构成,隐式接口通常由有效表达式组成, 比如,
1 template<typename Widget,typename Other>
2 void DoSomething(Widget& w, const Other& someNasty)
3 {
4     if( w.size() > 0 && w != someNasty) //someNastyT可能是是T类型的某一实例,也可能不是
5     {
6         Widget temp(w);
7         temp.normalize();
8         temp.swap(w);
9     }
10 }
  这看似要求:
  类型T需要支持size、normalize、swap函数,copy构造函数,可以进行不等比较
  类型T是在编译期模板进行具现化时才表现出调用不同的函数,此时对接口的调用就表现出了编译期时多态。
  但是,
  size函数并不需要返回一个整型值以和10比较,甚至都不需要返回一个数值类型,唯一的约束是它返回一个类型为X的对象,且X对象和int类型(数值10的类型)可以调用一个operator >,这个operator>也不一定非要一个X类型的参数不可,它可以通过隐式转换能将X类型转为Y类型对象,而只需要Y类型可以和int类型比较即可(好绕口,请看,这也侧面印证了模板编程编译错误很难解决)。
  同样类型T并不需要支持operator!=,而只需要T可以转为X类型对象,someNastyT可以转为Y类型对象,而X和Y可以进行不等比较即可。
  动态多态和静态多态的比较
  静态多态
  优点:
  由于静多态是在编译期完成的,因此效率较高,编译器也可以进行优化;
  有很强的适配性和松耦合性,比如可以通过偏特化、全特化来处理特殊类型;
  最重要一点是静态多态通过模板编程为C++带来了泛型设计的概念,比如强大的STL库。
  缺点:
  由于是模板来实现静态多态,因此模板的不足也就是静多态的劣势,比如调试困难、编译耗时、代码膨胀、编译器支持的兼容性
  不能够处理异质对象集合
  动态多态
  优点:
  OO设计,对是客观世界的直觉认识;
  实现与接口分离,可复用
  处理同一继承体系下异质对象集合的强大威力
  缺点:
  运行期绑定,导致一定程度的运行时开销;
  编译器无法对虚函数进行优化
  笨重的类继承体系,对接口的修改影响整个类层次;
  不同点:
  本质不同,静态多态在编译期决定,由模板具现完成,而动态多态在运行期决定,由继承、虚函数实现;
  动态多态中接口是显式的,以函数签名为中心,多态通过虚函数在运行期实现,静态多台中接口是隐式的,以有效表达式为中心,多态通过模板具现在编译期完成
  相同点:
  都能够实现多态性,静态多态/编译期多态、动态多态/运行期多态;
  都能够使接口和实现相分离,一个是模板定义接口,类型参数定义实现,一个是基类虚函数定义接口,继承类负责实现;
  附上本次测试的所有代码:
  Static_Dynamic_Polymorphism.cpp
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号