五、对象数组和对象指针
1. 对象数组的定义和使用
-
将具有相同类类型的对象有序的集合在一起构成了对象数组,以一维对象数组为例,定义形式为:
Point points[100]; //类名 对象数组名[常量表达式];
说明:
在建立对象数组的时候需要调用构造函数,有多少个对象就要调用多少次构造函数
如果对象数组所属类有带参数的构造函数,可用初始化列表按顺序调用构造函数,使用复制初始化来初始化来初始化每个数组元素
如果对象数组所属类有单个参数时,定义数组时可以直接在初始化列表中提供实参
Point P[3] = {Point(1,2), Point(5, 6), Point(7,8)}; Student S[5] = {20, 21, 19, 20, 19}; // Student类只有一个数据成员
对象数组创建时若没有初始化,则其所属类要么有合成默认构造函数,要么定义无参数的构成函数或全部参数为默认参数的构造函数
对象数组的初始化究竟是什么形式,本质上取决于所属类的构造函数
如果对象数组含有析构函数,那么建立对象数组时按每个元素出现的顺序调用构造函数,按相反的顺序调用析构函数
2. 指向对象的指针
-
对象内存单元的起始地址就是对象的指针,可以定义一个指针变量,用来存放对象的指针,指向类对象的指针变量的定义为
类名 * 对象指针变量名 = 初值;
-
示例
class Time{ public: Time(int h=0, int m=0, int s=0): hour(h), minute(m), second(s) { } void set(int h=0, int m=0,int s=0) { hour=h; minute=m; second=s; } int hour, minute, second; }; int main() { Time now(12, 0, 0), *pt; pt=&now; return 0; }
-
可以通过对象指针访问对象和对象的成员。
pt->set(13, 13,0); pt->hour =1;
3. 类成员指针
-
对象的成员也要占用存储空间,因此可以使用指向对象成员的指针变量,一般形式为
int *ptr = &now.hour; // 数据成员类型 *指针变量名 = 初值;
-
指针可分为四类
- C语言的普通指针:数据指针、函数指针
- C++的成员指针:数据成员指针、成员函数指针
-
成员指针与类的类型和成员的类型相关,可用来指向类的非静态成员,因为静态成员不属于任何类的对象,可用普通指针
数据成员指针
-
定义数据成员指针的一般形式为:
数据成员类型 类名::*指针变量名 = 成员地址初值;
-
示例
class Data{ public: typedef unsigned int index; // 类型成员 char get() const; // 成员函数 char get(index st, index eb) const; // 成员函数 string content; // 数据成员 index cursor, top, bottom; // 数据成员 }; int main() { string Data::*ps = &Data::content; // 指向Data::content的成员指针 }
成员函数指针
-
定义成员函数指针时必须保证三个方面与其所指的函数的类型相匹配
- 成员函数的形参类型和数目,包括成员是否为const
- 返回类型
- 类类型
定义形式如下:
//返回类型 (类名::*指针变量名)(形参表) = 成员地址初值 // 或 //返回类型 (类名::*指针变量名)(形参表)const = 成员地址初值 char (Data::*pmf)() const = &Data::get; //指向Data::get()的成员函数指针 typedef char (Data::*GETFUNC)(Data::index, Data::index)const; // 为成员指针使用类型别名 GETFUNC pfget = &Data::get; //定义成员函数指针
使用类成员指针
-
通过对象成员指针引用 类类型对象.*成员指针
-
通过指针成员指针引用 类类型指针->成员指针
-
示例
Data d, *p=&d; // p是指向对象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); // 指针间接引用对象通过成员函数指针间接调用成员函数
4. 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);
-
示例
#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 += a; 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指针,即如下
void MovePoint(Point *const this, int a, int b);
-
MovePoint函数便成了
void MovePoint(int a, int b) { this->x += a; this->y += b; }
-
-
什么时候用到this指针
- 在类的非静态成员函数返回类对象成员本身的时候,直接使用
return *this
- 当参数与数据成员名相同时,如
this->n = n
class Point{ public: Point(float x, float y) { this->x = x; this->y = y; } private: float x, y; }
- 在类的非静态成员函数返回类对象成员本身的时候,直接使用
-
this指针的const限定
-
假设Point类有getX这样一个非静态函数
double Point::getX(); // 编译后 double getX(Point *const this); // this指针的指向不允许改变,所以this指针原本就是const指针
-
如果成员函数是常函数
double Point::getX()const; // 编译后 double getX(const Point *const this); //既不允许this指针的指向,也不允许改变this指向的内容
-