讨厌的函数指针

前面曾写过一篇恼人的函数指针(一),总结了普通函数指针的声明、定义以及调用,还有函数指针数组,函数指针用作返回值等。但是作为C++的研读,我发现我漏掉了一个最重要的内容,就是指向类成员的指针,这里将做相应补充(相关代码测试环境为vs 2010)。

指向类成员的指针总的来讲可以分为两大类四小类(指向数据成员还是成员函数,指向普通成员还是静态成员),下面一一做介绍:

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

1、指向类成员函数的指针

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

a)参数类型和个数

b)返回值类型

c)所属的类类型(特别之处)

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

明白了这点,接下来就简单了。

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

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

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

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

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

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

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

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

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

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

 1 class A;
 2 typedef void (A::*NONSTATICFUNCPTR)(int);    //typedef
 3 
 4 class A
 5 {
 6 public:
 7     void NonStaticFunc(int arg) 
 8     {
 9         nonStaticMember = arg; 
10         cout<<nonStaticMember<<endl;
11     }
12 private:
13     int    nonStaticMember;
14 };
15 
16 int main()
17 {
18     NONSTATICFUNCPTR funcPtr= &A::NonStaticFunc;
19 
20     A a;
21     (a.*funcPtr)(10);        //通过对象调用
22 
23     A *aPtr = new A;
24     (aPtr->*funcPtr)(10);    //通过指针调用
25 
26     return 0;
27 }

2、指向类数据成员的指针

成员函数搞懂了,数据成员也就easy了,只要判断以下两点是否一致即可:

a)数据成员类型

b)所属的类类型

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

 1 class A;
 2 typedef int (A::*NONSTATICDATAPTR);        //typedef
 3 
 4 class A
 5 {
 6 public:
 7     A(int arg):nonStaticMember(arg){}
 8     int    nonStaticMember;
 9 };
10 
11 int main()
12 {
13     NONSTATICDATAPTR dataPtr= &A::nonStaticMember;
14     
15     A a(10);
16     cout<<a.*dataPtr;        //通过对象引用
17 
18     A *aPtr = new A(100);
19     cout<<aPtr->*dataPtr;    //通过指针引用
20 
21     return 0;
22 }

运行结果,当然是各自输出10和100啦。

二、指向类的静态成员的指针

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

所以,指向类的静态成员的指针就是普通的指针。

看下面的例子就明白了:

 1 typedef const int *STATICDATAPTR;    
 2 typedef int (*STATICFUNCPTR)();        //跟普通函数指针是一样的
 3 
 4 class A
 5 {
 6 public:
 7     static int StaticFunc() { return staticMember; };
 8     static const int staticMember = 10;
 9 };
10 
11 int main()
12 {
13     STATICDATAPTR dataPtr = &A::staticMember;
14     STATICFUNCPTR funcPtr = &A::StaticFunc;
15     
16     cout<<*dataPtr;            //直接解引用
17     cout<<(*funcPtr)();    
18 
19     return 0;
20 }

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


写到此,简单总结一下就是:

1)静态的和普通的函数指针没啥区别;

2)非静态的加一个类局限一下即可。

不知道以后还会不会有函数指针相关的内容,先到此完结吧。

有错误欢迎指正,我会及时修改^^。

(完)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于双向链表的逆序排列函数实现,双向链表的数据结构包括一个双向链表节点结构体`ListNode`和一个双向链表结构体`LinkedList`: ```c typedef struct ListNode { int val; // 节点值 struct ListNode* prev; // 指向前一个节点的指针 struct ListNode* next; // 指向后一个节点的指针 } ListNode; typedef struct LinkedList { ListNode* head; // 指向双向链表头节点的指针 ListNode* tail; // 指向双向链表尾节点的指针 } LinkedList; LinkedList* reverseLinkedList(LinkedList* list) { if (list == NULL || list->head == NULL) { return list; } ListNode* curr = list->head; ListNode* prev = NULL; ListNode* next = NULL; while (curr != NULL) { next = curr->next; curr->next = prev; curr->prev = next; prev = curr; curr = next; } list->tail = list->head; list->head = prev; return list; } ``` 该函数接收一个双向链表的指针,首先判断输入是否为空或链表是否为空,如果是则直接返回。否则,定义三个指针变量`curr`、`prev`、`next`,分别指向当前节点、前一个节点和后一个节点。在遍历链表时,将当前节点的next指针指向前一个节点,将当前节点的prev指针指向后一个节点,然后将prev指针指向当前节点,curr指针指向next节点,继续遍历,直到遍历完整个链表。最后将链表的头节点指向原来的尾节点,尾节点指向原来的头节点,返回链表的指针即可。 需要注意的是,由于该函数涉及到修改链表节点的指针指向,因此在调用该函数前需要确保链表中的每个节点都已经正确地初始化其prev和next指针。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值