对C++中指针类型的研究

C++中的“指针”实质上是指针类型的数据, 可以是“变量”也可以是“常量”,它里面存储的数值常被解释成为内存里的一个地址。人们往往只是简单的说“指针”,没有带“常量”或“变量”二字,那么, 一个“指针”到底是指常量呢还是指变量呢?这个问题要根据它所属的那个整句来进行判断。C++中的指针按照它所指向的对象可以划分为变量指针、数组指针、 函数指针、对象指针、类的成员数据指针和类的成员函数指针。

  1. 变量指针

  高级编程语言里都是通过变量来管理软件运行时内存中的变量数据,并不直接提供这个变量在虚拟内存中居体的位置,这里我们可以使用一些手段,得到一个变量在虚拟内存中的位置,这个位置就是我们这里所说的“变量指针”[1]

  设type代表任意一种基本类型说明符,X是该类型的变量,则:

  (1)X的指针常量为&X。

  (2)一个type型指针变量P的声明格式为:type *P;

  (3)使P指向X,也就是说用&X向P赋值的格式为:

  ①用&X初始化;

  ②在声明了P后向P赋值。

  2. 数组指针

  数组名本身就是一个指针,指向数组的首地址。注意这是声明定长数组时,其数组名指向的数组首地址是常量。而声明数组并使某个指针指向其值指向某个数组的地址(不一定是首地址),指针取值可以改变。

  指向数组的一个指针,如int (*p)[10] 表示一个指向10个int元素的数组的一个指针。

  设A是一个有3行4列个type型变量元素的一个二维数组,则:

  (1)A有两个意义:①表示这12个type型变量构成的整体。②表示A<0>的地址,即A=&A<0>。

  A<0>也有两个意义:①表示A的第一行的4个type型变量构成的整体(A中左下标为0的一行元素);②表示A<0><0>的地址。

   (2) ①声明一个指向type型的有3行4列个元素的二维数组的指针P的格式为:type(*P)<3><4>;②声明一个指向 type型的有4个元素的一维数组指针P1的格式为: type(*P1)<4>;③声明一个指向type型变量的指针P2的格式为:type  *P2。

  (3)①使P指向A的 方式为:用&A初始化P或在声明了P后向 P赋值;②使P1指向A<1>的方式为:用“A+1”初始化P1或在声明了P1后向P1赋值;③使P2指向 A<2><1>的方式为:用&A<2><1>初始化P2或在声明了P2后向P2赋值。

  (4)用 A和*来表示A<2><1>的表达式为*(*(A+2)+1),表示A<0><0>的表达式为**A。

   (5)按3,①用P和*来表示A<2><1>的表达式为*(*(*P+2)+1);②用P1和*来表示 A<2><1> 的表达式为*(*(P1+1)+1);③用P2和*来表示A<0><0>的表达式为:*(P-6);

  用P、P1和P2来访问A的元素有很多优越性,如它们及其表达式可以进行++运算和- -运算而指针常量却办不到。

  3. 函数指针

   函数指针是指向函数的指针变量。因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一 样,这里是指向函数。高级语言在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。有了指向函数的指针变量后,可用该指针变量调 用函数,就如同用指针变量可引用其他 类型变量一样。

  设一个函数的原型为:type fun (),则:

  (1)fun()的指针常量为fun

  (2)声明一个数据类型为type,形参表为FL的函数指针P的格式为:type (P)(FL);

  (3)用一个数据类型为type形参表为FL的函数指针只能指向数据类型为type形参表为FL的函数。按(1)和(2),用P指向fun()的方式为:用fun初始化P或在声明P后向P赋值。

  (4)用P而不用fun来调用fun()的格式为:P(和FL对应的实参表);

  4. 对象指针

  对象指针指向类的成员的指针。在C++中,可以说明指向类的数据成员和成员函数的指针。

  指向数据成员的指针格式如下:

  <类型说明符><类名>::*<指针名>

指向成员函数的指针格式如下:

  <类型说明符>(<类名>::*<指针名>)(<参数表>)[1]

  设t是A类的一个对象,a和f( )分别是A的一个公有变量成员和公有函数成员,则:

  (1)t的指针常量为&t;

  (2)声明一个指向A类的对象的指针P的格式为:A*P;

  (3)使P指向t的方式为:用&t初始化P或者在声明了P后再向P赋值。

  (4)①用P而不用t来表示t. a的格式为:P->a;

  ②用P而不用t来访问f( )的格式为:P->f( );

  由于类不是运行时存在的对象。因此,在使用这类指针时,需要首先指定A类的一个对象,然后,通过对象来引用指针所指向的成员。例如,给pc指针所指向的数据成员c赋值8,可表示如下:

  A a;  a.*pc = 8;

  其中,运算符.*是用来对指向类成员的指针来操作该类的对象的。

  5. 类的数据成员指针

  类的数据成员指针并不涉及到内存地址,它只是引用了一个类的某个成员,而不是一个具体的对象的某个成员,类没有内存地址,因此类成员的指针也不 能指向内存的某个地方,它通常只是一个偏移量(offset)。由于标准C++没有定义类成员的指针的实现,故大多数是用一个整数来表示这个偏移 量。[2]

  设t是A类的一个对象,a是A的一个非静态type型成员数据,s是A的一个静态type1型成员数据,则:

  (1)①A::a的相对指针常量为&A:: a;②A::s的物理指针常量为&A:: s

  (2)①可以指向A类的type型非静态成员的指针P1的声明格式为:type  A::*P1; ②可以指向A类type型静态成员的指针P2的声明格式为:type 1*p2;

  (3)①使P1指向A::a的方式为:用& A:: a初始化P1或在声明了P1后向P1赋值;②使P2指向A::s的方式为:用& A:: s初始化P2或在声明了P2后向P2赋值。

  (4)①用P1而不用a来访问t.a的格式为:t .* p1;②用P2而不用s来访问t.s的表达式为*P2

  6. 类的函数成员指针

  在C++程序中,很多函数是成员函数,即这些函数是某个类中的一部分。你不可以像一个普通的函数指针那样指向一个成员函数,正确的做法应该是,你必须使用一个成员函数指针。一个成员函数的指针指向类中的一个成员函数,并和以前有相同的参数声明如下:

  float (SomeClass::*my_memfunc_ptr)(int, char *);

  对于使用const关键字修饰的成员函数,声明如下:

  float (SomeClass::*my_const_memfunc_ptr)(int, char *) const;

  这里使用了特殊的运算符(::*),而“SomeClass”是声明中的一部分。[3]

  设t是A类的一个对象,f(FL1)是A类的一个type型非静态的函数成员,g(FL2)是A类的一个type1型静态函数成员,则:

  (1)①A::f( )的相对指针常量为A::f;②A::g( )的物理指针常量为A::g

  (2)①可以指向A的非静态type型形参表为FL1的函数成员的指针P1的声明格式为type( A::*P1)(FL1);②可以指向A的静态type1型形参表为FL2的函数成员的指针P2的声明格式为:type1(*P2)(FL2)

  (3)①使P1指向A::f( )的方式是:用A::f初始化P1或在声明了P1后向P1赋值;②使P2指向A::g( )的方式是:用A::g初始化P2或者在声明了P2之后向P2赋值。

  (4)①用P1而不用f来访问t.f()的格式为:(t.*p1)(实参表);这里的“*”为指针说明符而不是指针运算符;②用P2而不用g()来访问t.g( )的格式为:P2(实参表);

  成员函数指针有一个限制:它们只能指向一个特定的类中的成员函数。对每一种参数的组合,需要有不同的成员函数指针类型,而且对每种使用const修饰的函数和不同类中的函数,也要有不同的函数指针类型。

  一个成员函数指针可以被设置成0,并可以使用“==”和“!=”比较运算符,但只能限定在同一个类中的成员函数的指针之间进行这样的比较。任何 成员函数指针都可以和0做比较以判断它是否为空。与函数指针不同,不等运算符(<, >, <=, >=)对成员函数指针是不可用的。

  7. 指针的特点

  (1)可以用类型定义来隐藏复杂的成员指针语法

  (2)可以在不必知道函数名的情况下,通过成员指针调用对象的成员函数。

  (3)数据指针+n=数据指针+(n×这个数据的字节数)(n=整数,n为小数不合法)。如:①设P为一个int型指针,则P+2=P的 值+8(2×4);②设P1为一个有3行2列个int型变量元素的数组的指针,则P1+2=P1的值+2×24;③设A类有16个字节,P2是一个A类的 指针,则P2+2=P2的值+2×16。

  (4)下面的表达式不合法:

  函数指针+n。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值