Essential C++学习记录&笔记整理31(指针,指向类成员函数)

呜呼,终于到了最后一章!

指向类成员函数的指针

  • 指向类成员函数的指针,总归是函数指针,有返回类型,有参表。只不过这个指针指向的函数是某个类里的成员函数。
  • 指向类成员函数的指针要标明它所指的是哪个类,如:
void (num_sequence::*pm)(int)=0;

这里pm这个指针就是指向的num_sequence这个类的成员函数。而且pm指针的初始值为0,表示他不指向任何成员函数。这个成员函数的返回值是void,参表只有单参,参数类型是int

  • 好你可能会问我有嘛用?就像函数指针一样,有嘛用?对吧。
    先回顾下函数指针有什么用
    在这里插入图片描述
    成员函数指针也是如此,通过一个指针,指向某类的成员函数,其目的还是方便调用,少些几个字母什么的,比如int (num_sequence::*pm)(int)=&num_sequence::woshinibaba;然后我要是输出woshinibaba这个成员函数(假设这个成员函数参表是单参且该成员函数的功能是cout<<东西),我就pm(实参);就完了。
  • 如果你觉得我上面那个比如的例子中给函数指针定义并初始化的语法比较复杂,那可以用typedef来简化一下:
typedef void(num_sequence::*PtrType)(int);
PtrType pm=0;

以PtrType代替void(num_sequence:😃(参表),岂不美哉。

指向成员函数指针的运用

class num_sequence{
public:
	typedef void(num_sequence::*PtrType)(int);
	//简化成员函数指针的定义。
	void fibonacci(int);
	void pell(int);
	void lucas(int);
	void triangular(int);
	void sequence(int);
	void pentagonal(int);
	//六个数列产生新元素的算法函数
	//...
private:
	PtrType _pmf;//定义一个成员函数指针,可以指向num_sequence
	//类的任何一个成员函数(返回类型、参表和成员函数指针定义时的
	//返回类型、参表都适配)
  • 好的,如果我们想取得某个成员函数的地址赋给成员函数指针,就这样写
PtrType pm=&num_sequence::fibonacci;

=右边一个&运算符,然后类作用域运算符指明成员函数指针指的哪个类的成员函数,左边pm这个成员函数指针的类型就是PtrType,即void(num_sequence::)(int)

  • 如果要指定成员函数指针的值,其实大同小异,只不过你定义完了再给这个成员函数指针赋值嘛!
pm=&num_sequence::triangular;
  • 然后咱们就这个例子说明一些其他注意事项,现在,我为了方便和简化,我就将上述六个数列成员函数的地址存放在一个静态数组中static const int num_seq=7;static PtrType func_tbl[num_seq];为了不重复计算每个数列的元素,我用一个静态类成员(static vector<vector<int> >seq;)来存放六个数列(六个vector)
    注意:static vector<vector<int> >,相当于一个二维数组。seq是一个vector,这个vector里每个元素又是一个vector,用来存放int型元素。我必须要在<int> >这两个>>之间加一个空格,否则编译错误。
    为什么?这是基于maximal munch编译规则,maximal munch规则要求运算符组成的序列按合法的序列最长的哪个解释。
    比如我没在>>之间加一个空格,**因为>>是个合法的运算符序列,因此编译器会看成>>(输出运算符)而非> >。**举个例子,你就明白了
a+++p//被编译器解释为===>a++ + p;

所以,你要创建二维vector时,一定要在两个>之间加一个空格!!!!!!!

//因为PtrType是个嵌套类型,所以在num_sequence这个类之外对它所做的任何访问操作,都必须在PtrType前加类名::
typedef void(num_sequence::*PtrType)(int);//我再给嵌套定义一遍,
//防止你看不懂代码
const int num_sequence::num_seq;
vector<vector<int> >num_sequence::seq(num_seq);
num_sequence::PtrType num_sequence::func_tbl[num_seq]=
{0,
&num_sequence::fibonacci,
&num_sequence::pell,
&num_sequence::lucas,
&num_sequence::triangular,
&num_sequence::square,
&num_sequence::pentagona
};//定义个成员函数指针数组,用以存放指向每个num_sequence类里的成员函数的指针

上述就是成员函数指针数组的定义和初始化。

  • 类成员函数指针和函数指针的一个不同点是,类成员函数指针必须通过同类的类对象来调用。
num_sequence ns;
num_sequence *pns=&ns;
PtrType pm=&num_sequence::fibonacci;

如果我们想通过类对象(ns)调用(num_sequence)类的私有成员**(成pm类成员函数指针所指的类成员函数的定义里会涉及到类的私有成员的操作**),就可以这么写

(ns.*pm)(pos);
//这就是类成员函数指针必须通过同类的类对象来调用(ns.*pm)

.*是个成员选择指针运算符,类对象专有的运算符,注意写法,就按照上面哪一行的写法就行,不要丢括号。

类对象指针专有的运算符是->*,写法如下:

(pns->*pm)(pos);
//pns是类对象指针。前面定义了,自己看。而ns是类对象。
//如果我们想通过类对象指针(pns)调用(num_sequence)类的私有成员
//(成pm类成员函数指针所指的类成员函数的定义里
//会涉及到类的私有成员的操作),就可以这么写

你看,像不像结构体的结构成员变量的调用?举个例子:

struct Node{
	int data;
	struct Node* next;
}Lnode,*LinkList;
int e=10000;
Lnode a;
a.data=e;
Linklist b;
b->data=e;

再通过一个实例来给大家说明一下类成员函数指针的使用把!

int num_sequence::elem(int pos)
{
	//类成员函数的定义
	if(!check_integrity(pos))
	{
		return 0;//在这个类成员函数里使用了其他的本类的类成员函数
	}
	if(pos>_elem->size())
	//先说明一些注意,来帮助你解读下面的代码
	//vector<int>* _elem;
	//_elem指向存着数列元素的vector
	//PtrType _pmf;
	//_pmf指向num_sequence类的数列成员函数(或说产生数列元素的
	//成员函数像fibonacci(int)这样的成员函数)
	{
		(this->*_pmf)(pos);
		//this指针指向调用这个定义的成员函数的
		//类对象。如果用户传进来一个合理的位置值(没走第一个if,但
		//走第二个if),而且目前vector形式的数列所存储的元素
		//没有包含这个数列位置上的元素,就调用_pmf这个类成员函数
		//指针,产生新的数列(由_elem这个vector<int>型指针指向)的元素
	}
	return (*_elem)[pos-1];
	//返回_elem这个vector<int>型指针指向的数列(目前这个数列的元素扩展到了pos-1(vector内部从下标0开始存储)这个位置上)
}
//此成员函数(elem())功能就是看是否需要扩充数列元素到pos-1的位置上,
//需要就扩充,不需要就什么也不做,
//原封不动地返回数列(_elem指针指向这个数列)就完了。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值