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函数。这样来实现多种不同的函数签名。

 

posted on 2013-10-08 07:25  奎哥  阅读(378)  评论(0)    收藏  举报