1 kebianarr.cpp
/**
* 运算符重载实例:可变长整型数组
*
* 分析:
* CArray的对象代表一个数组,需要存放一个数组,那么数组存放在哪?需要使用动态分配的内存来存放数组元素,需要一个对象中有一个指针成员变量指向它。
* 动态分配内存也需要释放,因此在CArray类的析构函数中进行释放操作
*
* 赋值语句中赋值号‘=’需要重载
*
* a2是个对象,但是a2[]跟数组的使用方法一致,因此需要重载运算符[]
*
* CArray的复制构造函数
*
*
* */
#include <iostream>
#include "CArray.h"
using namespace std;
int main() // 要编写可变长整型数组类,使之能如下使用
{
CArray a; // 开始里的数组是空的
for(int i = 0; i < 5; i++)
a.push_back(i); // 1 要用动态分配的内存来存放数组元素,需要一个指针成员变量。 析构函数中去释放分配的这个内存
CArray a2, a3;
a2 = a; // 2 赋值语句的赋值号'='需要重载
for(int i = 0; i < a.length(); i++)
cout << a2[i] << " "; // 3 a2不是一个数组的名字,而是一个对象的名字,因此需要对运算符[]进行重载
a2 = a3; // a2是空的
for(int i = 0; i < a2.length(); ++i) // a2.length()返回0
cout << a2[i] << " ";
cout << endl;
a[3] = 100;
CArray a4(a); // 4 复制构造函数不能使用缺省的,需要自己编写复制构造函数
for(int i = 0; i < a4.length(); i++)
cout << a4[i] << " ";
return 0;
}
2 CArray.h
/**
* 写一个类考虑构造函数(类型转换构造函数、复制构造函数)、成员函数、析构函数、运算符重载
* */
#ifndef BEIDALESSON1_CARRAY_H
#define BEIDALESSON1_CARRAY_H
class CArray{
int size; // 数组元素的个数
int* ptr; // 指向动态分配的数组
public:
// 普通构造函数
CArray(int s = 0); // s 代表数组元素的个数 此处使用了缺省值
// 复制构造函数
CArray(CArray& a);
// 析构函数
~CArray();
// 用来在数组的尾部添加一个元素v
void push_back(int v);
// 用于数组对象间的赋值 实现深拷贝的操作
CArray& operator=(const CArray& n);
// 返回数组元素个数
int length();
// 运算符[]重载为CArray类的成员函数
// 作用:支持根据下表访问数组元素 例如 n = a[i], a[i] = 4这样的语句
// 返回C值为int不行!,不支持a[i] = 4; (非引用的函数返回值,不可以作为左值使用!) a[i]等价于 a.operator[](i); 返回对象a的成员指针ptr指向的动态内存的第i个元素。
//
int& operator[](int i);
};
#endif //BEIDALESSON1_CARRAY_H
3 CArray.cpp
//
// Created by z on 19-10-11.
//
#include <cstring>
#include "CArray.h"
// 构造函数有一个参数s,代表数组对象被初始化的时候,它里面就已经包含多少个元素了,前面看到s有一个缺省值是0,说明一个数组对象被初始化的时候,没有指定参数s的话,这个参数就是0,数组对象就是空的,没有任何元素。
CArray::CArray(int s):size(s) {
// 如果s == 0; 说明数组对象是空的,ptr=NULL,代表该数组对象中int* ptr成员指针变量不指向任何地方
// 如果s不等于0,需要动态分配一片存储空间
if(s == 0)
ptr = NULL; // int*型指针不指向任何地方
else
ptr = new int[s]; // 将new出来的整形数组的地址付给ptr
}
// 复制构造函数 需要完成深拷贝的工作,需要使得被初始化的那个对象的内容,变成跟a一样,这两个对象不能指向同样的存储空间
/**
* 为啥要自己写复制构造函数
* eg:
* a1 ptr ------> 11 14 9 8
* 如果不自己写复制构造函数,执行语句CArray a2(a1);产生效果如下
* a2 ptr ------>
* 11 14 9 8
* a1 ptr ------>
* 可知,a2对象中ptr指针与a1对象中ptr指针指向同一数组的地址,释放的时候会出现错误。
*
* 正确的结果应该是如下,他们指向不同内存空间,但是数组元素一样
* a1 ptr ------> 11 14 9 8
* a2 ptr ------> 11 14 9 8
* */
CArray::CArray(CArray &a) {
// 如果a.ptr是空数组 需要让初始化的这个对象的ptr指针指向的地方也变成一个空数组,size指定0,返回该对象。
if(!a.ptr)
{
ptr = NULL;
size = 0;
return;
}
// 如果对象a不是空数组,需要将被初始化里面的ptr成员变量指向一片新分配出来的存储空间,存储空间大小与a数组中一致
ptr = new int[a.size];
// 将a.ptr所指向的内容,拷贝到需要初始化对象的ptr所指向的地方去,一共拷贝多少个字节的内容,使用sizeof(int) * a.size个
memcpy(ptr, a.ptr, sizeof(int) * a.size);
// size成员变量也给赋值一下。
size = a.size;
}
// 析构函数 释放存储空间,释放之前判断一下ptr是否为空指针,不是空指针,再进行delete
CArray::~CArray() {
if(ptr)
delete[] ptr;
}
// 赋值运算符重载函数 返回值为CArray& 目的是为了符合赋值运算符的惯例(在C++中,赋值运算符的返回值是等号左边那个变量的引用)
CArray& CArray::operator=(const CArray &n) {
// 赋值号的作用是使得‘=’左边对象里存放的数组,大小和内容都和右边的对象一样
if(ptr == n.ptr) // 防止 a = a这样的赋值导致出错
return *this;
if(n.ptr == NULL) // 如果n中数组是空的
{
// 如果初始化的数组本身不是空的,需要先收回其存储空间
if(ptr)
delete[] ptr;
ptr = NULL;
size = 0;
return *this;
}
if(size < n.size) // 如果原有空间够大,就不用分配新的空间
{
if(ptr)
delete[] ptr;
ptr = new int[n.size];
}
memcpy(ptr, n.ptr, sizeof(int) * n.size);
size = n.size;
return *this;
}
// 运算符[]重载函数
int& CArray::operator[](int i) {
return ptr[i];
}
// 数组末尾添加元素v函数
void CArray::push_back(int v) {
if(ptr)
{
int* tmpPtr = new int[size +1]; // 重新分配空间
memcpy(tmpPtr, ptr, sizeof(int) * size); // 拷贝原数组内容
delete[] ptr;
ptr = tmpPtr;
}
else // 数组本身是空的
ptr = new int[1];
ptr[size++] = v; // 加入新的数组元素
}
// 返回数组长度函数
int CArray::length() {
return this->size;
}