?这个是按照北京大学郭老师c++程序设计所作的课堂笔记。
/*动态可变长数组(运算符重载)的使用
*/
#include<iostream>
using namespace std;
class CArray {
int size; //数组元素的个数,(有一个length成员函数,能输出数组的长度)
int* ptr; //指向动态分配的数组
public:
CArray(int s = 0); //构造函数,s代表数组元素的个数
CArray(CArray& a); //
~CArray();
void push_back(int v); //在数组尾部添加一个元素v
CArray& operator=(const CArray& a); //用于数组对象间的赋值
int length() { return size; } //返回数组元素个数
/*
下面函数的作用:
用以支持根据下标访问数组元素,如n=a[i]和a[i]=4这样的语句,
a[]a里面的数组元素在ptr指向的动态分配的空间中。
下面这个函数的类型是什么???
[]是双目运算符(一个在里面,一个在外面)只有一个参数,在成员函数中,数组的下标,在这个成员函数中运用
*/
int& operator[](int i) { //返回值的类型为什么是int的引用,为甚么int不行???
//用n=a[]可以,但是用a[]=4就是不可以了
//如果一个函数的返回值不是引用的话就不能作为=(赋值运算符)的左值、
//同时****希望能修改a[]的值,如果是一个数值则不会修改数值,只有是ptr[]的引用才能让a[]被修改
return ptr[i]; //返回一个数值,a[]的数值
}
};
CArray::CArray(int s) :size(s) { //构造函数,就已经包含多少元素//size()初始化列表
if (s == 0)
ptr = NULL;
else
ptr = new int[s];
}
CArray::CArray(CArray& a) { //复制构造函数,深拷贝
if(!a.ptr) { //主要用来判断如果指针是空指针的时候,
//进行出错处理和return 出去。说明有错误了。
ptr = NULL;
size = 0;
return; //return出去
}
ptr = new int[a.size];
memcpy(ptr, a.ptr, sizeof(int) * a.size);//将a.ptr中的内容复制到ptr中去,并且需要有多少字节的内容,sizeof(int)*a.size
size = a.size;
}
CArray::~CArray() { //释放空间
if (ptr)delete[]ptr; //判断是不是空指针,如果不是空指针就释放
}
CArray& CArray::operator=(const CArray& a) {//赋值号的作用是使“=”左边对象里存放的数组,大小和内容都和右边的一样
//返回值是carray的引用,是为了符合赋值号使用的惯例,在c++中赋值表达式的返回值本来就是赋值号左面的变量的引用,
//我们遵循这样的习惯,所以赋值号重载后的返回值仍然是CArray的引用
//如果不是这样的话那么在c++中左值并不是一个引用,而是一个返回的值,那么这个变量就不能作为一个赋值运算符的左值
if (ptr == a.ptr) //防止a=a这样的赋值导致出错(特判)
return *this; //跳出函数
if(a.ptr == NULL) { //引用值的数组
if (ptr) delete[]ptr; //ptr中的数组内容
ptr = NULL;
size = 0;
return *this;
}
if (size < a.size) {
if (ptr)
delete[]ptr;
ptr = new int[a.size];
}
memcpy(ptr, a.ptr, sizeof(int) * a.size); //其实这句话就执行了size>a.size,因为执行完上一个if语句后就来执行这个语句,
//并且最后一种情况和if(处理size<a.size)之后需要处理的是一样的东西,所以只需要写一个就行
size = a.size;
return*this;
}
void CArray::push_back(int v) { //这个比较低效应该先用比较长的存储空间(32),若不够再+32
if (ptr) { //在尾部加一个新的元素
int* temPtr = new int[size + 1]; //重新分配空间
memcpy(temPtr, ptr, sizeof(int) * size);//拷贝元素组内容
ptr = temPtr;
}
else//数组本来是空的
ptr = new int[1];
ptr[size++] = v;//加入新的数组元素
}
/*1.要用动态分配内存来存放数组,需要一个指针成员变量
2.动态分配的内存要释放,则需要一个析构函数
3.a2=a,则需要一个重载运算符=函数
4.a2[]成立则需要一个重载[]函数,因为a2是一个类
5.CArray a4(a)则需要一个复制构造函数,并且是深复制,如果是浅复制则动态分配的空间会出错
*/
int main() { //要编写的可变长数组,使之能如下使用
CArray a; //开始的数组是空的
for (int i = 0; i < 5; ++i)
a.push_back(i); //把五个整数加到数组里,有五个元素了
CArray a2, a3;
a2 = a; //a2是一个新的数组a的内容和a2的内容是一样的,只是存储空间不一样
//相互分开,此时用重载=运算符
for (int i = 0; i < a.length(); ++i) //打印a2,循环输出
cout << a2[i] << " ";
a2 = a3; //把a3复制给a2,但是此时a3是空的所以a2需要释放掉
for (int i = 0; i < a2.length(); ++i) //a2没有任何输出因为此时a2是一个空数组了,a2里面没有元素
cout << a2[i] << "";
cout << endl;
a[3] = 100; //赋值100
CArray a4(a); //复制构造函数
for (int i = 0; i < a4.length(); ++i)
cout << a4[i] << " "; //0 1 2 100 4
cout << endl;
int c[6] = { 0 };
CArray b;
for (int i = 0; i < 8; i++)
b.push_back(i);
b = a;
for (int i = 0; i < b.length(); i++)
cout << b[i]<<" ";
cout << endl;
return 0;
}
C++圣经《C++程序设计语言 特别版》(C++之父的著作)中说: ,C++之父认为 ,判断指针是否为空,用(p==NULL)或(p!=NULL)的格式 ?,这样写是不好的,提倡直接写(p)或(!p)的形式。 在win32开发中,if ( NULL == p )是极好的写法。但不要写成:if ( p == NULL )。 用if判断ptr是否为空指针的例子: int* ptr;?? ??? ??? ??? ??? ??? ?//ptr是一个指针 if(!a.ptr) {?? ??? ??? ??? ??? ??? ?//主要用来判断如果指针是空指针的时候, ?? ??? ??? ??? ??? ??? ??? ??? ??? ??? ?//进行出错处理和return 出去。说明有错误了。 ?? ??? ?ptr = NULL; ?? ??? ?size = 0; ?? ??? ?return;?? ??? ??? ??? ??? ??? ??? ?//return出去 ?? ?} ******************************************************************************* !逻辑非运算符,用来逆转操作数的状态,使真变假,使假变真? 例如: ?!ptr(ptr是一个指针),如果ptr=NULL,则该表达式为真; ******************************************************************************* int *P=NULL;//这里的NULL指的是指针指向的地址没有数值; ******************************************************************************* 赋值表达式: 左值:表达式可以引用到一个对象,并且这个对象是一块内存空间并可以检测和存储,这个表示即是左值。 右值:直接引用了一个存储在内存地址中的数据。 左值是一个对象或变量,代表一个固定地址,而没有固定地址的临时对象或临时变量既是右值,不能代表一个固定地址 ?
|