C++函数指针(包括指向成员函数的指针)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gc348342215/article/details/80295953

函数指针的初始化

函数如下:

int CompareString(const string& str1, const string& str2)
{
    return str1.compare(str2);
}

函数的初始化有两种方式:

第一种,也是最普遍的方式:

int (*CompareFunction)(const string&, const string&) = CompareString;

第二种,是使用 typedef 定义函数类型,这种写法有助于对代码的理解:

typedef int (*CompareFunctionType)(const string&, const string&);
CompareFunctionType CompareFunction = CompareString;

函数指针赋值

函数名可以理解为该类型函数的指针。当然,取地址操作符作用于函数名上也能产生指向该类型函数的指针。也就是说下面两种赋值都是可行的:

CompareFunctionType CompareFunction = CompareString;
CompareFunctionType CompareFunction = &CompareString;

函数调用

无论是用函数名调用,还是用函数指针调用,还是用显式的指针符号调用,其写法是一样的:

CompareString("abc", "cba");
CompareFunction("abc", "cba");
(*CompareFunction)("abc", "cba");

函数指针的数组

对于函数指针的数组,强烈建议使用typedef方式定义类型之后再使用,不然影响代码的阅读性,继续以以上例子为例:

//without typedef
int (*CompareFunctionArray[3])(const string&, const string&);
//with typedef
CompareFunctionType CompareFunctionTypeArray[3];

函数指针用做函数返回值的类型

到这一步,会发现 typedef 是多么的好用了。不然我是完全读不懂下面语句的意思的:

//without typedef
int (*func(int*, int))(const string&, const string&);

上面的声明,将func(int*, int)声明为一个函数,返回值为函数指针,函数类型为int (*)(const string&, const string&)。多么的晦涩啊!如果写成 typedef 就不用这么纠结了,足见 typedef 的作用:

CompareFunctionType func(int*, int);

上面所有的内容总结了普通函数指针的声明、定义以及调用,还有函数指针数组,函数指针用作返回值等。但是作为C++的研读,我发现我漏掉了一个最重要的内容,就是指向类成员的指针,这里将做相应补充。指向类成员的指针总的来讲可以分为两大类四小类(指向数据成员还是成员函数,指向普通成员还是静态成员),下面一一做介绍:

指向类的普通成员的指针(非静态)

指向类成员函数的指针

简单的讲,指向类成员函数的指针与普通函数指针的区别在于,前者不仅要匹配函数的参数类型和个数以及返回值类型,还要匹配该函数指针所属的类类型。总结一下,比较以下几点:
1. 参数类型和个数
2. 返回值类型
3. 所属的类类型(特别之处)

究其原因,是因为非静态的成员函数必须被绑定到一个类的对象或者指针上,才能得到被调用对象的this指针,然后才能调用指针所指的成员函数(我们知道,所有类的对象都有自己数据成员的拷贝,但是成员函数都是共用的,为了区分是谁调用了成员函数,就必须有this指针,this指针是隐式的添加到函数参数列表里去的)。明白了这点,接下来就简单了。

声明:与普通函数作为区分,指向类的成员函数的指针只需要在指针前加上类类型即可,格式为:

typedef 返回值 (类名::*指针类型名)(参数列表);

赋值:只需要用类的成员函数地址赋值即可,格式为:

指针类型名  指针名 = &类名::成员函数名;

注意:这里的这个&符号是比较重要的:不加&,编译器会认为是在这里调用成员函数,所以需要给出参数列表,否则会报错;加了&,才认为是要获取函数指针。这是C++专门做了区别对待。

调用:调用方法也很简单,针对调用的对象是对象还是指针,分别用.和->进行调用,格式为:

(类对象.*指针名)(参数列表);
(类指针->*指针名)(参数列表);

注意:这里的前面一对括号是很重要的,因为()的优先级高于成员操作符指针的优先级。

下面举个简单的例子就一目了然了:

class A;
typedef void (A::*NONSTATICFUNCPTR)(int);    //typedef

class A
{
public:
    void NonStaticFunc(int arg)
    {
        nonStaticMember = arg;
        cout<<nonStaticMember<<endl;
    }
private:
    int    nonStaticMember;
};

int main()
{
    NONSTATICFUNCPTR funcPtr= &A::NonStaticFunc;

    A a;
    (a.*funcPtr)(10);        //通过对象调用

    A *aPtr = new A;
    (aPtr->*funcPtr)(10);    //通过指针调用

    return 0;
}

指向类数据成员的指针

成员函数搞懂了,数据成员也就easy了,只要判断以下两点是否一致即可:
1. 数据成员类型
2. 所属的类类型

另外,声明、赋值还有调用方法等这些是和前面类似的,再举个例子吧:

class A;
typedef int (A::*NONSTATICDATAPTR);        //typedef

class A
{
public:
    A(int arg):nonStaticMember(arg){}
    int    nonStaticMember;
};

int main()
{
    NONSTATICDATAPTR dataPtr= &A::nonStaticMember;

    A a(10);
    cout<<a.*dataPtr;        //通过对象引用

    A *aPtr = new A(100);
    cout<<aPtr->*dataPtr;    //通过指针引用

    return 0;
}

运行结果,当然是各自输出10100啦。

指向类的静态成员的指针

类的静态成员和普通成员的区别在于,他们是不依赖于具体对象的,所有实例化的对象都共享同一个静态成员,所以静态成员也没有this指针的概念。所以,指向类的静态成员的指针就是普通的指针。看下面的例子就明白了:

typedef const int *STATICDATAPTR;
typedef int (*STATICFUNCPTR)();        //跟普通函数指针是一样的

class A
{
public:
    static int StaticFunc() { return staticMember; };
    static const int staticMember = 10;
};

int main()
{
    STATICDATAPTR dataPtr = &A::staticMember;
    STATICFUNCPTR funcPtr = &A::StaticFunc;

    cout<<*dataPtr;            //直接解引用
    cout<<(*funcPtr)();

    return 0;
}

最后注明一下,显然的,要使用(&类名::成员名)获取指向成员的指针,首先这个成员必须是对外可见的哦,即public的,不然是没有权限获取的。

总结

写到此,简单总结一下就是:
1. 静态的和普通的函数指针没啥区别;
2. 非静态的加一个类局限一下即可。

不知道以后还会不会有函数指针相关的内容,先到此完结吧。有错误欢迎指正,我会及时修改。

相关文档

C++成员函数指针的应用

猜你喜欢

转载自blog.csdn.net/gc348342215/article/details/80295953