一、函数

函数声明

在C++程序里,完成某件工作的一种典型方式就是调用一个函数去做那件事情。定义函数是你刻画怎样完成某个操作的
一种方式。一个函数只有在预先声明之后才能调用。
     在一个函数声明中,需要给出函数的名字,这个函数返回的值的类型,以及在调用这个函数时必顺提供的参数的个数和
类型。
     在函数声明中可以包含参数的名字。这样做可能对读程序的人有所帮助,但编译器将简单地忽略掉这样的名字。

函数定义

在程序里调用的每个函数都必需在某个地方定义(仅仅一次)。
     在函数的定义里,可以存在不使用的参数,这在实际工作中常常能看到的情况,如:

void g(const char* key,const char*);

如上所示,根本不使用的参数可以采用不予命名的方式明示。典型情况是,出现未命名参数的原因是做过代码的简化,或者是计划在将来做功能扩充。对于这两种情况,虽然不使用但还是让参数留在那里,就能保证那些调用的地方不会受到修改的影响。

内联函数

如果在函数的前面加上inline关键字。如:

inline int f(int n)
{return n;
}

inline描述符是建议编译器,要求它试着把所有的f()函数的调用在线化。使用内联函数可以提高执行速度,但是会增加代码的体积。一般来说,内联机制适用优化小的,只有几行的而且经常被调用的函数。使用内联函数应该把声明和定义放在一起,并且应该放在头文件里,这样方便编译器能够在调用时是可见的。

注:inline函数
1. 函数执行步骤:
a)将参数压栈
b)执行函数体
c)清除栈
内联函数省略了a和c,因此是高效的。
注意:即使定义了内联函数,也不一定是内联,如for循环,编译器不会将含有for循环的函数当为内联。
2. 99%内联函数放在头文件中,但也可以放在cpp文件中,这适用于不需要外部文件访问内联函数时。
3. 在头文件中,对类的函数声明和实现,编译器会自动将函数设置为内联函数。

参数传递

指针和引用选择:out 参数,当传出的参数可能是null时用指针,如果确定有值可以用引用

数组参数

当我们需要传递一段连续地、类型相同的数据时,我们可以用数组作为参数。注意,将数组作为函数的参数时,实质传递的是数组首元素的指针。这也意味着,对数组参数的某个元素的修改,将改变实际参数数组中那个元素的值。
如:int func(int a[],int elemSize);

返回值

绝不能返回指向局部变量的指针,如:

int* fp() {
int local = 3;
return &local;
}

也绝不能返回局部对象的引用,如:

const string& f(const string& s)
{
string ret = s;
return ret;
}

递归

分两种:

1)自身调用自身

2)A调用B,B调用A

指向函数的指针

#include <iostream>using namespace std;void Fun1(int n)
{cout << "Fun1\n";
}void Fun2(int n)
{cout << "Fun2\n";
}void Fun3(int n)
{cout << "Fun3\n";
}typedef void (*Fun)(int n);void main()
{Fun fun = &Fun1;fun(1);fun = Fun2;(*fun)(2);fun = Fun3;fun(3);
}

如上代码:
1)(*fun)代表函数,fun代表函数指针。在c语言中函数调用必须使用(*fun),但c++中可以不带*。
2)fun = &Fun1;  //如果是全局函数可以使用 & 或者不使用,因为函数名本身即是首地址。但是成员函数必须使用&,这是因为成员函数并不是一个函数,而是一个变量。

成员函数调用看下例:

#include <iostream>using namespace std;void Fun1(int n)
{cout << "Fun1\n";
}void Fun2(int n)
{cout << "Fun2\n";
}void Fun3(int n)
{cout << "Fun3\n";
}typedef void (*Fun)(int n);class CA
{typedef int (CA::*pClassFun)(int, int);            //函数指针定义public:int max(int a, int b){return a > b ? a : b;}int min(int a, int b){return a < b ? a : b;}int Result(pClassFun fun, int a, int b){return (this->*fun)(a, b);                     //this 必不可少;因为fun不是全局变量,所以*不可缺少
    }
};void main()
{CA ca;int a = 3;int b = 4;printf("member fun \n");printf("max result: %d\n", ca.Result(&CA::max, a, b));printf("min result: %d\n", ca.Result(&CA::min, a, b));
}

虚函数中如果使用 指向成员函数的指针 较为麻烦,因此成员函数指针较少使用,而一般用委托代替。

二、委托

1、引入fastdelegate库

文章地址:http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible

下载地址:http://www.codeproject.com/KB/cpp/FastDelegate/FastDelegate_src.zip

#include "FastDelegate.h"
using namespace fastdelegate;
typedef FastDelegate<void(void)>Callback;

2、库的使用

#include <iostream>
#include "FastDelegate.h"
using namespace fastdelegate;
typedef FastDelegate<void(void)>Callback;void GlobeFunc()
{printf("GlobeFunc()\n");
}static void StaticFunc()
{printf("StaticFunc()\n");
}struct Test1
{static void ClassStaticFunc(){printf("Test1::ClassStaticFunc()\n");}void MemberFun(){printf("Test1::MemberFun()\n");}virtual void VirtualMemberFun(){printf("Test1::VirtualMemberFun()\n");}
};struct Test2: public Test1
{void VirtualMemberFun(){printf("Test2::VirtualMemberFun()\n");}
};void main()
{Test1 t1;Test2 t2;Callback cb;cb.bind(GlobeFunc);cb();cb = Callback(StaticFunc);cb();cb.bind(Test1::ClassStaticFunc);cb();cb = Callback(&t1, &Test1::MemberFun);            //此处Test1::MemberFun前必须有&
    cb();cb.bind(&t1, &Test1::VirtualMemberFun);            //此处Test1::MemberFun前必须有&
    cb();cb.bind(&t2, &Test1::VirtualMemberFun);            //此处Test1::MemberFun前必须有&
    cb();
}

运行结果:
GlobeFunc()
StaticFunc()
Test1::ClassStaticFunc()
Test1::MemberFun()
Test1::VirtualMemberFun()
Test2::VirtualMemberFun()

3、多播

#include <iostream>
#include "FastDelegate.h"
using namespace fastdelegate;
typedef FastDelegate<void(void)>Callback;void GlobeFunc()
{printf("GlobeFunc()\n");
}static void StaticFunc()
{printf("StaticFunc()\n");
}struct Test1
{static void ClassStaticFunc(){printf("Test1::ClassStaticFunc()\n");}void MemberFun(){printf("Test1::MemberFun()\n");}virtual void VirtualMemberFun(){printf("Test1::VirtualMemberFun()\n");}
};struct Test2: public Test1
{void VirtualMemberFun(){printf("Test2::VirtualMemberFun()\n");}
};struct DelegateLink
{DelegateLink *next, *prev;float order;            //权重值,在0.0~1.0之间,权重值越小,函数越优先被调用
    Callback fDelegate;DelegateLink(){}DelegateLink(const Callback& dlg) : fDelegate(dlg){}void insert(DelegateLink* node, float order){DelegateLink *walk = next;//根据权重值,找到插入链表位置while(order >= walk->order && walk->next != this){walk = walk->next;}if (order >= walk->order){//insert after walknode->prev = walk;node->next = walk->next;walk->next->prev = node;walk->next = node;}else{//insert before walknode->prev = walk->prev;node->next = walk;walk->prev->next = node;walk->prev = node;}node->order = order;}void unlink(){next->prev = prev;prev->next = next;}
};class MultiDelegate
{
private:DelegateLink mList;Callback& getDelegate(DelegateLink *link){return link->fDelegate;}public:MultiDelegate(){mList.next = mList.prev = &mList;mList.order = 0.5f;}~MultiDelegate(){while(mList.next != &mList){DelegateLink *ptr = mList.next;ptr->unlink();delete ptr;ptr = NULL;}}bool isEmpty() const{return mList.next ==&mList;}bool contains(const Callback &dlg, float order)const{for (DelegateLink *ptr = mList.next; ptr != &mList; ptr = ptr->next){if (ptr->fDelegate ==dlg && ptr->order == order){return true;}return false;}}void add(const Callback &dlg, float order = 0.5F){mList.insert(new DelegateLink(dlg), order);}void remove(const Callback &dlg, float order){for (DelegateLink *ptr = mList.next; ptr != &mList; ptr = ptr->next){if (ptr->fDelegate == dlg && ptr->order == order){ptr->unlink();delete ptr;ptr == NULL;return;            }}}void MultiDelegate::trigger(){for (DelegateLink *ptr = this->mList.next; ptr != &this->mList; ptr = ptr->next){this->getDelegate(ptr)();}}
};void main()
{MultiDelegate md;Test1 test1;Test2 test2;md.add(Callback(GlobeFunc));md.add(Callback(StaticFunc));md.add(Callback(Test1::ClassStaticFunc));md.add(Callback(&test1, &Test1::MemberFun));md.add(Callback(&test1, &Test1::VirtualMemberFun));md.add(Callback(&test2, &Test2::VirtualMemberFun));        //md.add(Callback(&test2, &Test1::VirtualMemberFun));运行结果一致
    md.trigger();
}

运行结果:
GlobeFunc()
StaticFunc()
Test1::ClassStaticFunc()
Test1::MemberFun()
Test1::VirtualMemberFun()
Test2::VirtualMemberFun()

3、扩展

以上代码的回调函数限制了返回类型必须是void, 参数必须是void。如果要破除限制,要用到模板特化技术。

思路:将MultiDelegate抽象为MultiDelegateBase基类,去掉MultiDelegate::trigger函数,add、remove函数则作为模板参数,派生类继承MultiDelegateBase,并实现trigger函数。这样来实现多种不同的函数签名。

转载于:https://www.cnblogs.com/wangkl/p/3356490.html

C++编程--函数与委托(2)相关推荐

  1. 对C#下函数,委托,事件的一点理解!

    <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 今天一来是有点 ...

  2. Dotnet的局部函数和委托的对比

    上一篇说了一下委托,这篇来说说局部函数和委托的对比.   把委托和局部函数放成前后篇,是因为这两个内容很像,用起来容易混. 需要了解委托相关内容,可以看这一篇 [传送门]   使用委托表达式(Lamb ...

  3. 翻译连载 | 附录 C:函数式编程函数库-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇...

    为什么80%的码农都做不了架构师?>>>    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS> ...

  4. linux 编程函数原型与用法

    函数原型以及部分实例应用 --------------------------------------------------------------------------------------- ...

  5. 高阶函数、委托与匿名方法

    高阶函数.委托与匿名方法 高阶函数.委托与匿名方法 作者 赵劼 发布于 2009年4月17日 下午6时35分 高阶函数(higher-order function)是指把另一个函数作为参数或返回值的函 ...

  6. MySQL5_存储过程-sql编程-函数-触发器-用户管理

    文章目录 MySQL_存储过程-sql编程-函数-触发器-用户管理 建立表 1.存储过程(procedure) (1)创建存储过程 (2)参数的类别 (3)删除存储过程 (4)查看存储过程的信息 (5 ...

  7. linux网络编程函数解析之——setsockopt / getsockopt用法

    linux网络编程函数解析之--setsockopt / getsockopt用法 工程中无线传输方面的东西用到了setsockopt(),getsockopt().网上相关博客很多,而且类似,原文出 ...

  8. 程序设计C语言函数定义,编程函数的定义之C语言

    编程函数的定义之C语言 类型标识符指明了本函数的类型,函数的类型实际上是函数返回值的类型.接下来,小编为您介绍了编程函数的定义之C语言,感谢您的阅读! 无参函数的定义 无参函数定义的`一般形式如下:类 ...

  9. Linux服务器 - Socket编程函数_accept函数

    Socket编程函数 accept函数 #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int a ...

最新文章

  1. 中国高校4篇研究今日同时登上Nature!清华北大上交浙工大等在列
  2. Conda创建环境失败:CondaHTTPError: HTTP 000 CONNECTION FAILED
  3. python主成分分析相关系数_python如何进行主成分分析
  4. .NET Core 2.1的重大缺陷延长了.NET Core 2.0的寿命
  5. 触发Full GC执行的情况 以及其它补充信息
  6. Echarts 自定义数据视图
  7. WinForm------GridControl单元格内容修改外表样式
  8. 飞行计算机人机工程,人机工程学版
  9. Flask+Gunicorn(协程)高并发的解决方法探究
  10. TMS320C55x的寄存器
  11. 芯片烧录软件Android版,HiTool官方版
  12. 软件测试工程师经典面试题
  13. android expandablelistview横向,ExpandableListView的使用多级列表
  14. android 死亡阴影,英雄无敌3死亡阴影
  15. OpenGL教程——windows安装openGL
  16. “二十一天好习惯”第一期-20
  17. Docker基础:指定USER的容器中获得root用户的方法
  18. uniapp实现app的强制更新
  19. 杭州-SQL杭州国迈软件有限公司笔试题
  20. 【nvidia Xavier】感受gpu算力

热门文章

  1. setTimeOut与setInterval的区别
  2. snort 使用mysql的安装
  3. burst什么意思_为什么Windows/iOS操作很流畅而Linux/Android却很卡顿呢?
  4. svpwm仿真_【好物推荐】《现代永磁同步电机控制原理及MATLAB仿真》
  5. iphone7无服务_iphone7无服务无信号怎么办
  6. 全站仪与计算机之间的数据传输,必看!全站仪数据传输的三种方式详解,都安排得明明白白(上)...
  7. Linux用户和用户组和文件权限介绍
  8. tomcat 在WIN10 上运行出现500错误的解决方法
  9. 3-29Pytorch与autograd梯度与机器学习
  10. 制造业数字化转型的困难_智能制造如何助力企业转型升级?百家制造业企业共谋数字化转型路...