C++编程--函数与委托(2)
一、函数
函数声明
在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)相关推荐
- 对C#下函数,委托,事件的一点理解!
<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 今天一来是有点 ...
- Dotnet的局部函数和委托的对比
上一篇说了一下委托,这篇来说说局部函数和委托的对比. 把委托和局部函数放成前后篇,是因为这两个内容很像,用起来容易混. 需要了解委托相关内容,可以看这一篇 [传送门] 使用委托表达式(Lamb ...
- 翻译连载 | 附录 C:函数式编程函数库-《JavaScript轻量级函数式编程》 |《你不知道的JS》姊妹篇...
为什么80%的码农都做不了架构师?>>> 原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS> ...
- linux 编程函数原型与用法
函数原型以及部分实例应用 --------------------------------------------------------------------------------------- ...
- 高阶函数、委托与匿名方法
高阶函数.委托与匿名方法 高阶函数.委托与匿名方法 作者 赵劼 发布于 2009年4月17日 下午6时35分 高阶函数(higher-order function)是指把另一个函数作为参数或返回值的函 ...
- MySQL5_存储过程-sql编程-函数-触发器-用户管理
文章目录 MySQL_存储过程-sql编程-函数-触发器-用户管理 建立表 1.存储过程(procedure) (1)创建存储过程 (2)参数的类别 (3)删除存储过程 (4)查看存储过程的信息 (5 ...
- linux网络编程函数解析之——setsockopt / getsockopt用法
linux网络编程函数解析之--setsockopt / getsockopt用法 工程中无线传输方面的东西用到了setsockopt(),getsockopt().网上相关博客很多,而且类似,原文出 ...
- 程序设计C语言函数定义,编程函数的定义之C语言
编程函数的定义之C语言 类型标识符指明了本函数的类型,函数的类型实际上是函数返回值的类型.接下来,小编为您介绍了编程函数的定义之C语言,感谢您的阅读! 无参函数的定义 无参函数定义的`一般形式如下:类 ...
- Linux服务器 - Socket编程函数_accept函数
Socket编程函数 accept函数 #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> int a ...
最新文章
- 中国高校4篇研究今日同时登上Nature!清华北大上交浙工大等在列
- Conda创建环境失败:CondaHTTPError: HTTP 000 CONNECTION FAILED
- python主成分分析相关系数_python如何进行主成分分析
- .NET Core 2.1的重大缺陷延长了.NET Core 2.0的寿命
- 触发Full GC执行的情况 以及其它补充信息
- Echarts 自定义数据视图
- WinForm------GridControl单元格内容修改外表样式
- 飞行计算机人机工程,人机工程学版
- Flask+Gunicorn(协程)高并发的解决方法探究
- TMS320C55x的寄存器
- 芯片烧录软件Android版,HiTool官方版
- 软件测试工程师经典面试题
- android expandablelistview横向,ExpandableListView的使用多级列表
- android 死亡阴影,英雄无敌3死亡阴影
- OpenGL教程——windows安装openGL
- “二十一天好习惯”第一期-20
- Docker基础:指定USER的容器中获得root用户的方法
- uniapp实现app的强制更新
- 杭州-SQL杭州国迈软件有限公司笔试题
- 【nvidia Xavier】感受gpu算力
热门文章
- setTimeOut与setInterval的区别
- snort 使用mysql的安装
- burst什么意思_为什么Windows/iOS操作很流畅而Linux/Android却很卡顿呢?
- svpwm仿真_【好物推荐】《现代永磁同步电机控制原理及MATLAB仿真》
- iphone7无服务_iphone7无服务无信号怎么办
- 全站仪与计算机之间的数据传输,必看!全站仪数据传输的三种方式详解,都安排得明明白白(上)...
- Linux用户和用户组和文件权限介绍
- tomcat 在WIN10 上运行出现500错误的解决方法
- 3-29Pytorch与autograd梯度与机器学习
- 制造业数字化转型的困难_智能制造如何助力企业转型升级?百家制造业企业共谋数字化转型路...