before|正文之前:
c++实验代码及学习笔记(八)
你好! 这是一个高程实验课的代码记录及学习笔记。我将记录一些重要的知识点、易错点。但是作为大学生,水平很低,敬请指点教导、优化代码。
1问题
本次课我们学习了类的动态分配。类的动态分配与普通的malloc、free不同,取而代之的是new和delete。本质上非常相似,只是malloc、free不能调用构造与析构函数。所以创建对象数组时,我们要使用new和delete操作。
“应用任意大小和类型”,则用到了我们新学习的概念:模板。类的模板非常实用,充分体现了c++泛型编程、多态性的优越性。
同时自己实现一个动态数组类,则是对数组、运算符重载等知识的进一步巩固。
话不多说,咱们打板就唱 打码就上。
2精讲
模板
参考文章:精品【转】 C++模板详解
模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。
使用模板的目的就是能够让程序员编写与类型无关的代码。它可以给出一种模板类型T,用于声明成员变量、形参等等,调用时注明所需类型(如int)就可以创建类模板对象。十分方便。
给出具体例子,简单明了:
1、类模板的格式为:
template<class 形参名,class 形参名,…> class 类名
{ … };
如
template<class T> //模板形参
class A //模板类的声明
{public:
T a;
T b;
T hy(T c, T &d);
};
2、类模板对象的创建:比如一个模板类A,则使用类模板创建对象的方法为
A<int> m
在类A后面跟上一个<>尖括号并在里面填上相应的类型,这样的话类A中凡是用到模板形参的地方都会被int 所代替。当类模板有两个模板形参时创建对象的方法为A<int, double> m;类型之间用逗号隔开。
3、在类模板外部定义成员函数的方法为:
template<模板形参列表> 函数返回类型 类名<模板形参名>::函数名(参数列表){函数体},
template<class T1,class T2> void A<T1,T2>::h(){}。
4、提醒注意:模板的声明或定义只能在全局,命名空间或类范围内进行。即不能在局部范围,函数内进行,比如不能在main函数中声明或定义一个模板。
实现一个数组类
首先,我们要构思这个类的成员数据和函数,实现什么功能,解决什么问题。
-
成员数据
数组的大小(精细一点可以区分数组的容量和数组实际大小)size
数组指针 *arr -
构造函数
含参构造函数,初始化,new数组
析构函数,delete对象,释放空间 -
运算符重载
=赋值
[ ]像正常数组那样使用对象数组 -
数组基本操作
分配内存、重定义数组大小、打印数组、增加减少插入元素(并未实现)
对指针合理初始化
内存管理:初始化指针
template <typename T>
class Array
{
private:
int _size;
T* arr;
public:
Array() :_arr(NULL), _size(0) //对指针合理初始化
{}
Array(int size)
{
arr = new T[size];
_size = size;
if (!this->arr)
{
cout << "失败" << endl;
exit(1);
}
for (int i = 0; i < size; i++)
{
arr[i] = 0;
}
}
如果非构造函数,则需要先删除内存。因为_data可能内存可能已被分配,不删除就会造成内存泄漏。
void create(int size)
{
if (_data)
delete[] _data;
_data = new int[size];
_size = size;
}
深复制与浅复制
为什么要重写复制构造函数?
因为默认复制构造函数,执行的是浅复制,对指针name拷贝后会出现两个指针指向同一内存的局面。
而深复制,则是重新分配一个新的内存空间,避免内存泄漏。
Array(const Array<T> &obj)//拷贝构造函数
{
T* array = new T[obj._size];
arr = array;
_size = obj._size;
for (int i = 0; i < _size; i++)
{
arr[i] = obj[i];
}
}
代码实现
#include <iostream>
#include <stdlib.h>
#include <cstring>
using namespace std;
template <typename T>
class Array
{
private:
int _size;
T* arr;
public:
Array() :_arr(NULL), _size(0) //对指针合理初始化
{}
Array(int size)
{
arr = new T[size];
_size = size;
if (!this->arr)
{
cout << "失败" << endl;
exit(1);
}
for (int i = 0; i < size; i++)
{
arr[i] = 0;
}
}
Array(int size, const T* array)
{
_size = size;
this->arr = new T[_size];
if (!this->arr)
{
cout << "失败" << endl;
exit(1);
}
strcpy_s(this->arr,_size, array);
//strcpy(this->arr,array);
}
Array(const Array<T> &obj)//拷贝构造函数
{
T* array = new T[obj._size];
arr = array;
_size = obj._size;
for (int i = 0; i < _size; i++)
{
arr[i] = obj[i];
}
}
Array<T>& operator=(const Array<T>&obj) //赋值构造函数
{
if (this != &obj)
{
for (int i = 0; i < _size; i++)
{
arr[i] = obj[i];
}
}
return *this;
}
~Array()
{
if (arr != NULL)
{
delete[] arr;
arr = NULL;
}
}
public:
void resize(int size) //重新分配大小
{
T* array = new T[size];
int len = _size < size ? _size : size;
for (int i = 0; i < len; i++)
{
array[i] = arr[i];
}
T *temp = arr;
arr = array;
_size = size;
delete[] temp;
}
T& operator[](int i)
{
return arr[i];
}
const T& operator[](int i)const
{
return arr[i];
}
friend ostream& operator<< (ostream &out, const Array<T>&a)
{
for (int i = 0; i < a._size; i++)
{
out << a.arr[i] << " ";
}
out << endl;
return out;
}
void put()
{
for (int i = 0; i < _size; i++)
{
cin >> arr[i];
}
}
};
int main()
{
Array<int> arr1(10);
Array<int> arr2(20);
Array<char> arr3(10, "abcdefghi");
cout << "请输入10个数字" << endl;
arr1.put();
arr2.resize(10);
arr2 = arr1;
cout << arr1 << endl;
cout << arr2 << endl;
cout << arr3 << endl;
getchar();
getchar();
return 0;
}
最终效果
咱一言也说不尽这知识点呀,祝列位阖家欢乐,福寿康宁! 感谢大家阅读,鞠躬下台!