C/C++ 动态分配、类的模板与数组类构建实例

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;
}

最终效果

最终效果
咱一言也说不尽这知识点呀,祝列位阖家欢乐,福寿康宁! 感谢大家阅读,鞠躬下台!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值