to myself 的分类学习日志

做自己想做的事
posts - 232, comments - 6, trackbacks - 0, articles - 0

c++ pointer

Posted on 2010-09-17 11:56 kongkongzi 阅读(207) 评论(0)  编辑 收藏 引用 所属分类: c++ programming
一、数据指针
#include <iostream>

struct MyStruct
{
        
int key;
        
int value;
};

int sum(MyStruct* objs, int MyStruct::* pm, int count)
{
        
int result = 0;
        
for(int i = 0; i < count; ++i)
                result 
+= objs[i].*pm;
        
return result;
}

int main(void)
{
        MyStruct me[
10= 
        {
                {
1,2},{3,4},{5,6},{7,8},{9,10},{11,12},{13,14},{15,16},{17,18},{19,20}
        };

        
//计算10个MyStruct结构的value成员的总和: sum_value 值 为 110     (2+4+6+8++20)
        int sum_value = sum(me, &MyStruct::value, 10);
        std::cout 
<< "sum_value=" << sum_value << std::endl;

        
//计算10个MyStruct结构的key成员的总和:   sum_key 值 为 100       (1+3+5+7++19)
        int sum_key = sum(me, &MyStruct::key, 10);
        std::cout 
<< "sum_key=" << sum_key << std::endl;

        
return 0;
}
说明:int MyStruct::* pm,pm指向MyStruct中的任一数据成员。 要求MyStruct中的数据成员都是int型。


二、函数指针
#include <iostream>
#include 
<string>
using namespace std;

typedef unsigned 
int uint32;


class CNewFuncBase
{
public:
        
//virtual uint32 CreateNewFunc(void) = 0;
        
//virtual void DelteNewFunc(uint32 pObj) = 0;
        virtual void Update(void) { }
};


typedef CNewFuncBase
* (*pfv) ();
typedef 
void (*pff) (CNewFuncBase*);


pfv g_pfCreateNewFunc 
= NULL;
pff g_pfDeleteNewFunc 
= NULL;
CNewFuncBase
* g_pObj = NULL;

/*
 * 下面是设置具体的功能实例
 
*/

class CNewFuncInstance : public CNewFuncBase
{
public:
        
//uint32 CreateNewFunc(void) = 0;
        
//void DelteNewFunc(uint32 pObj) = 0;
        void Update(void) { printf("Update  \n"); }
};


CNewFuncBase
* CreateNewFunc1(void)
{
        CNewFuncBase
* pObj = new CNewFuncInstance();
        
return pObj;
}

void DeleteNewFunc1(CNewFuncBase* pObj)
{
        CNewFuncInstance 
*pInstance = (CNewFuncInstance *)pObj;
        delete pInstance;
        pObj 
= 0;
}



int main(void)
{
        g_pfCreateNewFunc 
= CreateNewFunc1;
        g_pfDeleteNewFunc 
= DeleteNewFunc1;

        
if (g_pfCreateNewFunc != NULL)
        {
                g_pObj 
= g_pfCreateNewFunc();
        }

        
if (g_pObj != NULL)
        {
                g_pObj
->Update();
        }

        
if (g_pfDeleteNewFunc != NULL && g_pObj != NULL)
        {
                g_pfDeleteNewFunc(g_pObj);
        }

        
return 0;
}
说明:实现回调的一种办法,利用派生和虚函数也可以实现回调。


三、成员函数指针(class members)
#include <vector>
#include 
<algorithm>
#include 
<functional>
#include 
<iostream>
using namespace std;

class A
{
public:
        A(
int v) { value = v; }
        
void doit() { cout << value << endl; }
        
static void call_doit(A& rThis)
        {
                rThis.doit();
        }
private:
        
int value;
};


int main()
{
        vector
<A> va;
        va.push_back(A(
1));
        va.push_back(A(
2));
        va.push_back(A(
3));
        va.push_back(A(
4));
        
//方法1:
        
//for_each(va.begin(), va.end(), &A::doit); //error
        
//方法2:
        for_each(va.begin(), va.end(), &A::call_doit);
        
//方法3:
        for_each(va.begin(), va.end(), mem_fun_ref<void, A>(&A::doit));

        
return 0;
}
        方法1,编译不能通过。for_each只允许具有一个参数的函数指针或函数对象,哪怕A::doit默认有一个this指针参数也不行。不是for_each没考虑到这一点,而是根本做不到!
  方法2,显然是受到了beginthread的启发,使用一个静态函数来转调用,哈哈成功了。但是不爽!这不是C++。
  方法3,呼,好不容易啊,终于用mem_fun_ref包装成功了成员函数指针。
  似乎方法3不错,又是类型安全的,又可以通用--慢着,首先,它很丑,哪有调用普通C函数指针那么漂亮啊(见方法2),用了一大串包装,又是尖括号又是圆括号,还少不了&号!其次,它只能包装不超过一个参数的函数!尽管它在for_each中够用了,但是你要是想用在超过一个参数的场合,那只有一句话:不可能的任务。

  是的,在标准C++中,这是不可能的任务。但事情并不总是悲观的,至少有许多第三方库提供了超越mem_fun的包装。如boost::function等等。但是它也有限制:它所支持的参数仍然是有限的,只有十多个,尽管够你用的了;同样,它也是丑陋的,永远不要想它能够简单的用&来搞定。

  也许,以失去美丽的代价,来换取质量上的保证,这也是C++对于函数指针的一种无奈吧……

  期待C++0x版本。它通过可变模板参数,能够让mem_fun的参数达到无限个……


四、函数对象
函数对象不是函数指针。但是,在程序代码中,它的调用方式与函数指针一样,后面加个括号就可以了。
函数对象实质上是一个实现了operator()--括号操作符--的类。
可以把附加数据保存在函数对象中,是函数对象的优势所在。

#include <iostream>

class less
{
public:
        less(
int num) : n(num) {}
        
bool operator()(int value)
        {
                
return value < n;
        }
private:
        
int n;
};


int main(void)
{
        
const int SIZE = 5;
        
int array[SIZE] = { 50309720};

        
// 找到小于数组array中小于10的第一个数的位置
        int* pa = std::find_if(array, array + SIZE, less(10)); // pa 指向 9 的位置
        std::cout << "*pa=" << *pa << std::endl;

        
// 找到小于数组array中小于40的第一个数的位置
        int* pb = std::find_if(array, array + SIZE, less(40)); // pb 指向 30 的位置
        std::cout << "*pb=" << *pb << std::endl;

        
return 0;
}


要想让一个函数既能接受函数指针,也能接受函数对象,最方便的方法就是用模板。

#include <iostream>

/* 统计数组中符合条件的数据个数 */
template
<typename FUNC>
int count_n(int* array, int size, FUNC func)
{
        
int count = 0;
        
for(int i = 0; i < size; ++i)
                
if(func(array[i]))
                        count 
++;
        
return count;
}

class less
{
public:
        less(
int num) : n(num) {}
        
bool operator()(int value)
        {
                
return value < n;
        }
private:
        
int n;
};


bool less10(int v)
{
        
return v < 10;
}


int main(void)
{
        
const int SIZE = 5;
        
int array[SIZE] = { 50309720 };

        std::cout 
<< "Using function object: result is " << count_n(array, SIZE, less(10)) << std::endl; // 2

        std::cout 
<< "Using function pointer: result is " << count_n(array, SIZE, less10) << std::endl; // 2

        
return 0;
}


另外,函数对象还有一个函数指针无法匹敌的用法:可以用来封装类成员函数指针!
因为函数对象可以携带附加数据,而成员函数指针缺少一个类实体(类实例)指针来调用,因此,可以把类实体指针给函数对象保存起来,就可以用于调用对应类实体成员函数了。

#include <iostream>

template
<typename O>
class memfun
{
public:
        memfun(
void(O::*f)(const char*), O* o): pFunc(f), pObj(o){}
        
void operator()(const char* name)
        {
                (pObj
->*pFunc)(name);
        }
private:
        
void(O::*pFunc)(const char*);
        O
* pObj;
};


class A
{
public:
        
void doIt(const char* name)
        { 
                std::cout 
<< "Hello " << name << "!" << std::endl;
        }
};


int main(void)
{
        A a;
        memfun
<A> call(&A::doIt, &a); // 保存 a::doIt指针以便调用
        call("Kitty"); // 输出 Hello Kitty!

        
return 0;
}

大功告成了,终于可以方便保存成员函数指针,以备调用了。

不过,现实是残酷的。函数对象虽然能够保有存成员函数指针和调用信息,以备象函数指针一样被调用,但是,它的能力有限,一个函数对象定义,最多只能实现一个指定参数数目的成员函数指针。
标准库的mem_fun就是这样的一个函数对象,但是它只能支持0个和1个参数这两种成员函数指针。如 int A::func()或void A::func(int)、int A::func(double)等等,要想再多一个参数如:int A::func(int, double),不好意思,不支持。想要的话,只有我们自已写了。
而且,就算是我们自已写,能写多少个?5个?10个?还是100个(这也太恐怖了)?
好在boost库提供了boost::function类,它默认支持10个参数,最多能支持50个函数参数(多了,一般来说这够用了。但它的实现就是很恐怖的:用模板部份特化及宏定义,弄了几十个模板参数,偏特化(编译期)了几十个函数对象。

----
C++0x已经被接受的一个提案,就是可变模板参数列表。用了这个技术,就不需要偏特化无数个函数对象了,只要一个函数对象模板就可以解决问题了。期待吧。


补充1:使用boost::functon和boost::bind

#include <iostream>
#include <map>
#include <string>
#include <boost/function.hpp>
#include <boost/bind.hpp>

class CSecuTradeHandler
{
public:
    void processOrderPost(const std::string& input_param, std::string &result)
    {
        std::cout << "called processOrderPost()" << std::endl;
    }
};


class CBankSecuTransHandler
{
public:
    void processBankSecuTrans(const std::string& input_param, std::string &result)
    {
        std::cout << "called processBankSecuTrans()" << std::endl;
    }
};


// typedef  void (*ProcessFunction)(const std::string&, std::string&);
typedef boost::function<void(const std::string&, std::string&)>  ProcessFunction;
typedef std::map<std::string, ProcessFunction> ProcessMap;
ProcessMap processMap_;

CSecuTradeHandler* pSecuTradeHandler = NULL;
CBankSecuTransHandler* pBankSecuTransHandler = NULL;

bool init()
{
    pSecuTradeHandler = new CSecuTradeHandler();
    processMap_["order_post"] = boost::bind(&CSecuTradeHandler::processOrderPost, pSecuTradeHandler, _1, _2);

    pBankSecuTransHandler = new CBankSecuTransHandler();
    processMap_["banksecu_trans"] = boost::bind(&CBankSecuTransHandler::processBankSecuTrans, pBankSecuTransHandler, _1, _2);

    return true;
}

bool dispatchCall(const std::string& func_flag, const std::string& input_param, std::string &result)
{
    ProcessMap::iterator pfn = processMap_.find(func_flag);
    if (pfn == processMap_.end()) 
    {
        return false;
    }

    (pfn->second)(input_param, result);    
    return true;
}


int main(int argc, char *argv[])
{
    init();

    std::string input_param = "{[]}";
    std::string result;
    std::string func_flag = "order_post";

    dispatchCall(func_flag, input_param, result);

    func_flag = "banksecu_trans";
    dispatchCall(func_flag, input_param, result);
    return 0;
}


补充2:使用C++11中std::function和std::bind,需要编译器支持。

#include <iostream>
#include <functional>
using namespace std;

class TestClass
{
public:
      int ClassMember(int a) { return a; }
      static int StaticMember(int a) { return a; }
};


int main()
{
        std::function<int(int)>  func;

        // 类成员函数
        TestClass testObj;
        func = std::bind(&TestClass::ClassMember, testObj, std::placeholders::_1);
        int result = func(40);
        cout << "类成员函数:" << result << endl;

        // 类静态函数
        func = TestClass::StaticMember;
        result = func(50);
        cout << "类静态函数:" << result << endl;

        return 0;
}



参考:http://www.cnblogs.com/ly4cn/