类成员指针
对象的成员要占用存储空间,因此也有地址,可以定义指向对象成员的指针变量,一般形式为:
数据成员类型 *指针变量名 = 初值;
例如:
int *ptr = &now.hour; //指向对象数据成员的指针变量
C++比C语言有更加严格的静态类型,更加强调类型安全和编译时检查
因此,C++的指针被分成数据指针,函数指针,数据成员指针,成员函数指针四种,而且不能随便相互转换。其中前两种是C语言的,称为普通指针(ordinary pointer);后两种是C++专门为类扩展的,称为成员指针(pointer to member)
成员指针与类的类型和成员的类型相关,它只应用于类的非静态成员。 由于静态类成员不是任何对象的组成部分,所以静态成员指针可用普通指针
1.数据成员指针
定义数据成员指针的一般形式为:
数据成员类型 类名:: *指针变量名 = 成员地址初值;
例如:
class Data { //Data类
public:
typedef unsigned int index; //类型成员
char get() const; //成员函数
char get(index st,index eb) const; //成员函数
string content; //数据成员
index cursor,top,bottom; //数据成员
};
指向content的指针的完全类型是“指向string类型的Data类成员的指针”,即:
String Data::*ps = &Data::content; //指向Data::content的指针
- 成员函数指针
定义成员函数的指针必须确保在三个方面与它所指函数的类型相匹配:
(1)函数形参的类型和数目,包括成员是否为const
(2)返回类型
(3)所属类的类型
定义的一般形式为:
返回类型(类名::*指针变量名)(形式参数列表)=成员地址初值;
或
返回类型(类名::*指针变量名)(形式参数列表)const = 成员地址初值;
- 例如“char get() const”成员函数的指针可以这样定义和初始化:
char (Data::*pmf)() const = &Data::get; //指向Data::get() 的成员指针
- 可以为成员指针使用类型别名,例如:
typedef char (Data::*GETFUNC)(Data::index,Data::index) const; //类型别名GETFUNC
- 这样指向get成员函数的指针的定义可以简化为:
GETFUNC pfget = &Data::get; //定义成员函数指针pfget
- 使用类成员指针
通过对象成员指针引用(. *)可以从类对象或引用及成员指针间接访问类成员,或者通过指针成员指针引用(-> *)可以指向类对象的指针及成员指针访问类成员
对象成员指针引用运算符左边的运算对象必须是类类型的对象,指针成员指针引用运算符左边的运算对象必须是类类型的指针,两个运算符的右边运算对象必须是成员指针
例如:
Data d, *p=&d; //指向对象d的指针
int Data::*pt = &Data::top; //pt为指向数据成员top的指针
int k = d.top; //对象成员引用,直接访问对象,直接访问成员,与下面等价
k = d.*pt; //对象成员指针引用,直接访问对象,间接访问成员
k = p->top; //指针成员引用,间接访问对象,直接访问成员,与下面等价
k = p->*pt; //指针成员指针引用,间接访问对象,间接访问成员
char (Data::*pmf)(int,int) const; //pmf为成员函数指针
pmf = &Data::get; //指向有两个参数的get函数
char c1 = d.get(0,0); //对象直接调用成员函数,与下面等价
char c2 = (d.*pmf)(0,0); //对象通过成员函数指针间接调用成员函数
char c3 = (p->*pmf)(0,0); //指针间接引用对象通过成员函数指针间接调用成员函数
this指针
除了静态成员函数外,每个成员函数都有一个额外的,隐含的形参this。在调用成员函数时,编译器向形参this传递调用成员函数的对象的地址。例如成员函数:
void Point::set(int a,int b) { x=a,y=b; } //成员函数定义
编译器实际上会重写这个函数为:
void Point::set(Point* const this,int a,int b)
{ this->x=a,this->y=b; }
对应的函数调用:
one.set(10,10); //调用成员函数
编译器实际上会重写这个函数调用为:
Point :: set(&one,10,10); //调用成员函数
this指针举例:
#include<iostream>
#include<string.h>
using namespace std;
class Point {
public:
Point(int a,int b) { x=a;y=b; }
void MovePoint(int a,int b) { x=x+a;y=y+b; }
void print() { cout<<"x="<<x<<",y="<<y<<endl; }
private:
int x,y;
};
int main()
{
Point pt1(10,10);
pt1.MovePoint(2,2);
pt1.print();
return 0;
}
- 当对象pt1调用MovePoint(2,2)函数时,即将pt1对象的地址传递给了this指针。MovePoint函数的原型应该是:
void MovePoint( Point *this, int a, int b);
- MovePoint函数中便成为:
void MovePoint(int a,int b) { this->x+=a;this->y+=b; }
- MovePoint函数体等价为:
pt1.x+=a; pt1.y+=b;
什么时候会用到this指针:
(1)在类的非静态成员函数中返回类对象本身的时候,直接使用 return *this;
(2)当参数与数据成员名相同时,如this->n=n(不能写成n=n)
this指针举例:
class point {
public:
point(float x,float y) {
this->x=x; //this->x 表示private中声明的x;x表示构造函数point(float x,float y)中的x
this->y=y; //this->y 表示private中声明的y;y表示构造函数point(float x,float y)中的y
}
private:
float x,y;
};
this指针的const限定:
- 假设Point类有getX这样一个非static函数:
double Point::getX();
- 编译以后形式如下:
double getX(Point *const this);
- 可以看出,this指针的指向不允许改变,所以this指针原来就是const指针
- 如果成员函数是常函数也就是下面的定义:
double Point::getX()const;
- 编译后会变成:
double getX(const Point *const this);
- 可以看出,即不允许改变this指针的指向,也不允许改变this指向的内容