当前位置: 首页 > news >正文

函数的弹性设计

函数的弹性设计

前言:
      实现函数的泛化及功能的弹性收缩是代码重用的技术基础也是编程人员应该有的编程思想,C++在语言范畴上也有很多支持其的机制。我们初窥编程时,当针对一个数据进行特定处理时,我们根据处理的流程在main函数的相应位置添相应的处理,当下一次需要对一个相同类型的另一数据处理时,我们在相应的置添加同样的代码用于处理,随着处理次数的增加,我们选择将这个功能抽象出来,这样我们就可以设计出一个对特定数据实现特定操作的函数,用于调用,从使代码更简洁,更易于理解。

      随着程序设计的深入,我们常常面对例如对另一种数据类型进行相同的处理或对多种数据进行类似的处理,我们也希望将此类问题抽象出来实现进一步的泛化,前者用模板实现后者用重载实现,事实上模板只需要在定义函数时说明一下并只需提供一个函数体,调用方法与调用其他函数一样;重载因为对数据的处理不完全相同,如针对一组输出操作,但有可能是输出一个字符串也有可能输出一数列的前两项,这样我们针对处理的参数类型和参数个数实现多个函数体。

 

以下是对一个函数的泛化过程:
1.函数最初声明
  void display(const vector<int> &vec)
  {
       cout<<...
  }
2.提供默认参数值
  设想这样一种情况,我们希望实现这样一种效果,我们默认将数据输出到屏幕

上,但我们希望可以选择将数据输出到文件中;
  void display(const vector<int> &vec, ostream &os=cout)
  {
      os<<...
  }
3.提供指针类型参数
  设想这样一种情况,我们希望可以选择是否将数据输出,也许我们程序中存在
  void display(const vector<int> &vec, ostream *os=0)
  {
      if(os)
        os<<...
  }
  比较2和3,当我们需要有选择的开启和关闭某个功能时传递指针参数,因为指

针可以不指向任何对象,但引用必须指向确定的对象;
4.模板函数
  设想这样一种情况我们希望可以选择输出字符型或整型或字符串型等等;
  template <typename elemtype>
  void display(const elemtype &, const ostream &os=cout)
  {
     os<<...
  }

5.函数重载
  设想这样一种情况,我们希望在一次调用中选择输出字符型或字符串型,或字

符串的一部分,这样需要设定不同类型的参数和参数个数;
  void display(char ch);
  void display(const string& );
  void display(const string& ,int, int);
    比较4和5,模板和函数重载代表程序设计的不同思想,模板体现程序设计的泛化,将有关类型的参数抽取出来,最终用一个函数体实现; 函数重载是将一个函数功能的弹性扩展,是一个函数能够实现多个功能,这样看来模板也是函数功能的弹性扩展,使一个函数可以操作各种类型的数据;
    我认为模板是将不同类型的数据进行相同的处理,对应一份函数体; 重载对数据的处理流程不同,对应多份函数体;二者的实现机制和效率及安全性也有不同之处,简单的说就是模板在编译时确定效率和安全性更高,重载在运行时确定;
    具体编程时我们要综合考虑函数泛化和功能的弹性级别,合理的选择模板和重载;
6.Pointer to Functions
    个人认为这里没有合适的中文翻译,有很多有关函数指针和指针函数的区别的解释,我认为英文更显得一目了然,首先是一个指针并且这个指针指向一个函数。那么Pointer to Functions和函数的弹性有什么联系呢?
    设想这样一种情况,这display()函数体中需要输出一个等差数列的前n项和;
    void display(ostream &os=cout)
    {
         os<<sum_equal_diff(n);
    }
    下一次我们需要输出一个等比数列前n项和,我们需要在定义一个函数;
    void display(ostream &os=cout)
    {
         os<<sum_equal_radio(n);
    }
    以后我们可能面对Fibonacci数列等等,因此我们希望在函数体内调用函数级别上的一个抽象概括(将调用函数参数化),这里我们就用到了我们的法宝,Pointer

to Functions;
我们的方式是把将要在函数体中调用的函数作为函数参数传递进来;
编程小技巧:
当我们要泛化某个操作时,我们可以将该操作抽象为一个函数并将其参数化;
  
  void display(int (sum_ptr)(int), ostream &os=cout)
  {
       oc<<sum_ptr(n);
  }
  具体调用的时候,我们可以定义一数组,内放Pointer to Functions,这样我们可以利用数组的索引技巧,将其用循环实现;


  int (*sum_ptr)(int)=0;

  int (*sum_array[])(int)={sum_dengcha,sun_dengbi,sum_fibonacci};
  for(int ix=0; ix!=3; ++ix)
  {
      sum_ptr=sum_array[ix];
      display(sum_ptr(n));
  }
  更进一步,我们可以利用枚举类型将整数和字符串关联起来,实现下标的辅助记忆,以更容易用Pointer to Functions调用函数,
  如enum ns_index{
    index_dengcha,index_dengbi,index_fibonacci};
  这样当我们获取等比的求和函数时就可以;
    sum_ptr=sum_array[index_dengbi];

总结:
    代码冗余不一定就应该赶尽杀绝,适当的代码冗余有利于函数的维护,因为软

件产品在整个生命周期内都有可能面对维护和修改,尤其由别人完成维护工作时

,可理解性就显的尤其重要了。
    Pointer to Functions将函数体内的一部分代码抽象出来实现函数嵌套调用的

弹性扩展,但我们的代码也变的更加晦涩,虽然通过枚举使其调用变得稍微直观

了一些但阅读起来仍很艰难。
    故当我们对某一个功能模块用函数实现时,我们需要综合运用默认参数,模板

,重载及Pointer to Functions,实现一个合适的弹性级别,并给出好的代码注

释,将函数功能,代码冗余及泛化程度达到一个黄金分割点的结合。

     
  
   

转载于:https://www.cnblogs.com/liuhao2638/archive/2012/03/27/2419701.html

相关文章:

  • 常见100个管理学定律
  • flexigrid
  • 内核开发基础——'make menuconfig' requires the ncurses libraries
  • COJ 1156 Switching bulbs
  • 配置Struts 2应用程序的安全功能
  • 程序猿的执业修养(四)——全力以赴,做到最好
  • 复杂报表中向上扩展
  • onMouseOut事件冒泡的问题解决
  • extjs 如何将局部的变量变为全局变量
  • ASP.net的身份验证方式FORMS
  • .net生成的类,跨工程调用显示注释
  • nginx 优化(突破十万并发)(转载记录)
  • 初等数论
  • 应用程序互相跳转
  • HDOJ 题目分类
  • 0基础学习移动端适配
  • 2017-09-12 前端日报
  • 345-反转字符串中的元音字母
  • HTML-表单
  • java8 Stream Pipelines 浅析
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • JS正则表达式精简教程(JavaScript RegExp 对象)
  • JS字符串转数字方法总结
  • Making An Indicator With Pure CSS
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • yii2中session跨域名的问题
  • 闭包--闭包作用之保存(一)
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 浅谈JavaScript的面向对象和它的封装、继承、多态
  •  一套莫尔斯电报听写、翻译系统
  • 做一名精致的JavaScripter 01:JavaScript简介
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • MyCAT水平分库
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • # Java NIO(一)FileChannel
  • # 计算机视觉入门
  • #传输# #传输数据判断#
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • #中的引用型是什么意识_Java中四种引用有什么区别以及应用场景
  • (C语言)逆序输出字符串
  • (floyd+补集) poj 3275
  • (rabbitmq的高级特性)消息可靠性
  • (搬运以学习)flask 上下文的实现
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (一) springboot详细介绍
  • (转)用.Net的File控件上传文件的解决方案
  • (转载)在C#用WM_COPYDATA消息来实现两个进程之间传递数据
  • .net 流——流的类型体系简单介绍
  • .NET建议使用的大小写命名原则
  • /deep/和 >>>以及 ::v-deep 三者的区别
  • /var/lib/dpkg/lock 锁定问题
  • :如何用SQL脚本保存存储过程返回的结果集
  • @DataRedisTest测试redis从未如此丝滑
  • [ Algorithm ] N次方算法 N Square 动态规划解决