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 walk node->prev = walk; node->next = walk->next; walk->next->prev = node; walk->next = node; } else { //insert before walk node->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函数。这样来实现多种不同的函数签名。
浙公网安备 33010602011771号