5.30C++:指向一维数组的指针、左值与右值,返回封装数组元素的引用

1 指向一维数组的指针

参考此篇文章:
C语言之指向一维数组的指针

int array[5] = {1, 2, 3, 4, 5}; // 定义数组
int (*ptr)[5] = &array; // 定义指向数组的指针

指针都是指向一种类型。所谓类型, 不过是对内存中数据的解释的约定。
对于int array[5] ,可以将 具有5个int元素的数组认为是一种类型,这种类型在内存上的特点是连续存储5个整形数据。
例如 int (*ptr)[5] ,ptr这个指针就是指向这种类型的指针,ptr是一个指向数组的指针

int (*ptr)[5]的形式是用来定义二维数组的指针的,用此方法将ptr指向一维数组的原因是:
一维数组array[5]可以看成是只有一个元素的二维数组,该二维数组的元素是int[5]类型的

array[5] = {{1,2,3,4,5}   }
当ptr是指向二维数组的指针时,*(ptr+i)表示第i行,ptr[i]表示第i行
*ptr == ptr[0] (这个二维数组的第一行,即进入这个一维数组) 
*ptr [1] == prt[0][1] == 一维数组的第2个元素 == 2

无法使用*(ptr+1) 或 ptr[1],因为这个二维数组只有一个元素


指向一维数组的指针的定义方式要使用&

 int b[3] = { 6,5,4 };
    int(*sb)[3] = &b;
    cout << sb << endl; //这六个输出值完全相等
    cout << *sb << endl;
    cout << sb[0] << endl;
    cout << b << endl;
    cout << &b << endl;
    cout << &b[0] << endl;

2 左值与右值,返回封装数组元素的引用

当一个对象被用作右值时,用的是对象的值(内容);当对象被用作左值时,用的是对象的身份(在内存中的位置)

右值只能出现在等号右边。

  1. a = 5 / a = b + c; 赋值运算符的左侧运算对象必须是左值,得到的结果也是一个左值
  2. int* p = &a; &取址运算符作用于一个左值运算对象(a),返回一个指向对象的指针,这个指针是一个右值(p)
  3. int a[5],这里a是首元素的地址,是右值
  4. *,[] 运算符求值结果是左值,*p是左值(可以直接修改指向对象的值),a[2]是左值,可以直接修改数组的第3个元素
  5. ++、- - 作用于左值,但只有前置版本的结果是左值(++a,–a)
  6. decltype(*p)的结果是int &,可以理解是因为 * p是左值
  7. decltyoe((变量))的结果永远是引用,注意是双层括号

int a[5] = {1,2,3,4,5}
a[0] = 100; 这个赋值操作中,a[0]是左值,100是右值
在这里插入图片描述

#include <iostream>
#include <cassert>
#include <typeinfo>
using namespace std;
class Point {
public:
	Point() : x(0), y(0) {
		cout << "调用Point类默认构造函数" << endl;
	}
	Point(int x, int y) : x(x), y(y) {
		cout << "调用Point类构造函数" << endl;
	}
	~Point() { cout << "调用Point类析构函数" << endl; }
	int getX() const { return x; }
	int getY() const { return y; }
	void move(int newX, int newY) {
		x = newX;
		y = newY;
	}
private:
	int x, y;
};
class ArrayOfPoints { //动态数组类
public:
	ArrayOfPoints(int size) : size(size) {
		cout << "调用ArrayOfPoints类构造函数" << endl;
		points = new Point [size]; //动态创建含size个元素的Point类型数组
	} 
	~ArrayOfPoints() {
		cout << "调用ArrayOfPoints类析构函数并delete动态分配内存" << endl;
		delete[] points;
	}
	Point& element(int index) { //一定要返回Point&,即左值
		assert(index >= 0 && index < size);
		return points[index];
	}
private:
	Point* points; //指向动态数组首地址
	int size; //数组大小
};
int main() {
	int count;
	cout << "输入要创建Point类对象的个数,存储在points指针指向的一维数组中: ";
	cin >> count;
	ArrayOfPoints aaa(count); //创建数组对象
	Point ppp(100, 100); //调用构造函数,非默认构造函数
	aaa.element(0).move(5, 0); //访问数组元素的成员
	aaa.element(1).move(15, 20); //访问数组元素的成员
	return 0;
}
结果:
输入要创建Point类对象的个数,存储在points指针指向的一维数组中: 2
调用ArrayOfPoints类构造函数
调用Point类默认构造函数
调用Point类默认构造函数

调用Point类构造函数 /符合后构造,先析构
调用Point类析构函数
调用ArrayOfPoints类析构函数并delete动态分配内存
调用Point类析构函数   /Point对象是动态内存分配的,是封装的,最后才析构
调用Point类析构函数
  1. 上述代码ArrayOfPoints类的构造函数中动态分配内存创建了一个有2个元素的Point类型数组,用points指针指向其首地址。
  2. 在自定义类中(ArrayOfPoints),不能直接用下标运算,要取得这个封装数组的元素,要使用element函数,通过返回值获得。(因为points是私有成员)
  3. assert函数验证输入的下标是否越界,如果输入合法,用输入的下标数值去找points[]这个数组的对应元素,注意,因为 Point* points = new Point [2],所以points这个指针可以当做该数组的数组名使用
  4. 返回值是points[index],返回类型是该元素的引用,可以在后续操作改变封装数组内部的元素(例如调用move函数改变points[0]、points[1]的x,y值),即返回引用类型是返回points[index]的左值。
  5. Point& element(int index)如果返回值不加引用,返回的是points[index]的副本,即points[index]的右值,后续怎么操作都不影响封装数组内部元素的值。
    如果去掉引用符号,即Point element(int index)
	aaa.element(0).move(5, 10);
	cout << aaa.element(0).getX() << endl;  //仍然返回0

move不起作用,因为element返回的是ArrayOfPoints类中封装的Point数组的副本,是右值,即对象以值传递的方式从函数返回,调用默认复制构造函数,对其进行move不会改变封装的数组的Point对象的x,y值。故aaa.element(0).getX() 的x不变,仍然是默认的0。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值