c++(三)

目录

引入

 一、函数模板

一般模板函数

特化模板函数

二、模板类Queue

模板类

成员模板函数

模板特化

模板成员函数特化

类模板特化

三、智能指针(模板类AutoPtr)

构造函数

拷贝构造函数

析构函数

赋值运算符重载

->、*等运算符重载

main.cpp


引入

C++最重要的特性之一就是代码重用,为 了实现代码重用,代码必须具有通用性。 通用代码需要不受数据类型的影响,并且可以自动适应数据类型的变化。这种程序设计类型称为参数化程序设计。模板是C++支持参数化程序设计的工具,通过它可以实现参数化多态性。所谓参数化多态性,就是将程序所处理的对象的类型参数化,使得一段程序可以用于处理多种不同类型的对象。

 一、函数模板

我们上一次学习的是函数重载,可以看出重载函数通常是对于不同的数据类型完成类似的操作。但如果这两个函数只有参数类型不同,功能完全一样,这时如果能写一段通用代码适用于多种不同数据类型,便会使代码的可重用性大大提高,从而提高软件的开发效率;使用函数模板就是为了这一目的。程序员只需对函数模板编写一次,然后基于调用函数时提供的参数类型,C++编译器将自动产生相应的函数来正确的处理该类型的数据。

函数模板的定义形式:

template<typename Type>
return_type fuc_name(parameter list)
{
    //函数具体实现
}

<>里的内容是由用逗号分隔的模板参数构成,typename可以接受一个类型参数,也可以用class关键字替代。

一般模板函数

我们可以通过一个简单的compare函数来体会模板函数的神奇之处:

template <class Type>
int compare(const Type& x1, const Type& x2)
{
	if (x1 < x2)
		return -1;
	if (x1 > x2)
		return 1;
	return 0;

}

模板函数只能在.h头文件中。定义编译器从实参的类型推导出函数模板的类型参数。例如,对于调用表达式compare(a,b),由于实参n为int类型,所以推导出模板中类型参数Type为int;对于调用表达式compare(a,b),由于实参n为double类型,所以推导出模板中类型参数Type为double。当类型参数的含义确定后,编译器将以函数模板为样板,生成一个函数,这一过程称为函数模板的实例化。

main.cpp

int main()
{


	cout << compare(6, 6)<<endl;
	cout << compare(6.11,6.22)<<endl;
	cout << compare(6.1,6.0)<<endl;
	return 0;

}

输出:

0
-1
1

特化模板函数

有时,遇到某些特定的参数类型我们又需要有另外不同的函数实现,来看一个不理想的结果:

int main()
{
	const char* a = "b";
	const char* b = "a";
	cout << compare(a, b) << endl;
	cout << compare(6, 6)<<endl;
	cout << compare(6.11,6.22)<<endl;
	cout << compare(6.1,6.0)<<endl;
	return 0;

}

输出:

-1
0
-1
1

很明显,字符串的对比并不是正确的结果;实际上程序是将两个字符串的地址进行对比,这并不是我们想要的对比方式。这时应该使用特化模板函数来实现:

template<>
int compare(const char* const& x1, const char* const& x2);
template<>
int compare<const char*>(const char* const& x1, const char* const& x2)
{
	return strcmp(x1, x2);
}

int main()
{
	const char* a = "b";
	const char* b = "a";
	cout << compare(a, b) << endl;
	cout << compare(6, 6)<<endl;
	cout << compare(6.11,6.22)<<endl;
	cout << compare(6.1,6.0)<<endl;
	return 0;

}

输出:

1
0
-1
1

得到了我们期望的结果。

二、模板类Queue

使用类模板使用户可以为类定义-种模式,使得类中的某些数据成员、某些成员函数的参数、返回值或局部变量能取不同类型(包括系统预定义的和用户自定义的)。类是对一组对象的公共性质的抽象,而类模板则是对不同类的公共性质的抽象,因此类模板是属于更高层次的抽象。由于类模板需要一种或多种类型参数,所以类模板也常常称为参数化类。当然,模板参数的实参也不总是可以用任何类型的。

类模板的定义形式:

template<class Type>
class class_name
{
    //类的具体实现
}

模板类

下面用一个Queue实例来了解一下类模板:

#ifndef QUEUE_H
#define QUEUE_H
#include <string>
#include <iostream>
using namespace std;

template<class Type> class Queue;
template<class Type> 
class QueueItem 
{
	//构造器初始化,这种初始化效率更高
	QueueItem(const Type& t) :item(t), next(0) {};

	//队列里的元素
	Type item;

	//队列里实例块的指针
	QueueItem* next;
	
	//友元类Queue
	friend class Queue<Type>;

	//输出运算符重载
	friend ostream& operator<<(ostream& os, const Queue<Type>& q);

public:
	//++运算符重载:指针的地址++
	QueueItem<Type>* operator++()
	{
		return next;
	}

	//*取值运算符重载:返回队列实例块中的元素
	Type& operator*()
	{
		return item;
	}
};
template<class Type> 
class Queue 
{
private:
	//头指针
	QueueItem<Type>* head;

	//尾指针
	QueueItem<Type>* tail;

	//销毁
	void destroy();
public:
	//无参构造器且初始化
	Queue() :head(0), tail(0) {};

	//构造一个队列 怎么构造:拷贝已有的整段Queue
	Queue(const Queue& q) :head(0), tail(0) { copy_items(q); }

	//构造一个队列 怎么构造:切片拷贝
	template<class It>Queue(It begin, It end) : head(0), tail(0)
	{
		copy_items(begin, end);
	}

	//拷贝整段队列,加在原有的队列后,但不能自己拷贝自己
	void copy_items(const Queue&);

	//切片拷贝,加在原有的队列后
	template<class It> void copy_items(It begin, It end);

	//切片拷贝,回删原有队列
	template<class It> void assign(It begin, It end);

	//重载赋值运算符
	void operator=(const Queue&);

	//获取头指针的元素
	const Type& front() const{ return head->item; }

	// 获取头指针
	const QueueItem<Type>* Head() const { return head; }

	// 获取尾指针
	 QueueItem<Type>* End()  { return (tail == NULL) ? NULL : tail; }

	//析构函数
	~Queue() { destroy(); }

	//进队
	void push(const Type&);

	//出队
	void pop();

	//判断队列是否为空
	bool empty()const
	{
		return head == 0;
	}

	//重载输出运算符
	friend ostream& operator<<(ostream& os, const Queue<Type>& q)
	{
		os << "[";
		//创建Queue里实例块指针
		QueueItem<Type>* p;
		//循环输出Queue里的元素
		for (p = q.head; p; p = p->next) {
			os << p->item << " ";
		}
		os << "]\n";
		return os;
	}


};


#endif // !QUEUE_H

模板类QueueItem是队列里的实例块,Queue是队列实例。

成员模板函数

类模板以外定义其成员函数,则要采用以下形式:

template<class Type>
return_type class_name<type>::fuc_name(parameter list)
{
    //函数具体实现
}

我们来看一下具体的实例:

//销毁
template<class Type>
void Queue<Type>::destroy() 
{
	//一直重复出队列的动作,直到队列为空
	while (!empty()) {
		pop();
	}

}

//元素进队列
template<class Type>
void Queue<Type>::push(const Type& val) 
{
	//创建元素为val的实列块
	QueueItem<Type>* pt = new QueueItem<Type>(val);

	//若队列为空,则新进入的实例块既是头指针也是尾指针
	if (empty()) {
		head = tail = pt;
	}
	else {
		//新进入的实例块放在尾指针后,尾指针指向它
		tail->next = pt;
		tail = pt;
	}
}

//元素出队列
template<class Type>
void Queue<Type>::pop() 
{
	//先进先出
	//找到头指针
	QueueItem<Type>* p = head;
	head = head->next;
	//删除p
	delete p;
}

//拷贝整段队列
template<class Type>
void Queue<Type>::copy_items(const Queue& orig) 
{
	//简单的找到头指针、next、push
	for (QueueItem<Type>* pt = orig.head; pt; pt = pt->next) {
		push(pt->item);
	}

}

//切片拷贝,加在原有的队列后
template<class Type>
template<class It> 
void Queue<Type>::copy_items(It begin, It end) 
{

	while (begin != end)
	{
		push(*begin);
		++begin;
	}
}

//切片拷贝,回删原有的队列
template<class Type>
template<class It>
void Queue<Type>::assign(It begin, It end)
{
	//先回删
	destroy();
	//再切片拷贝
	copy_items(begin, end);
}


template<class Type>
void Queue<Type>::operator=(const Queue& q)
{
	//要先判断是不是本身,不然是本身的话会出现逻辑错误
	if (this != &q) {
		//删除原队列
		destroy();
		//再拷贝另外的整段队列
		copy_items(q);
	}


}

这些我都是放在头文件里实现的。

main函数:

#include"Cmb.h"
#include"Queue.h"
#include<iostream>
using namespace std;

template<>
int compare<const char*>(const char* const& x1, const char* const& x2)
{
	return strcmp(x1, x2);
}

int main()
{
	//const char* a = "b";
	//const char* b = "a";
	//cout << compare(a, b) << endl;
	//cout << compare(6, 6)<<endl;
	//cout << compare(6.11,6.22)<<endl;
	//cout << compare(6.1,6.0)<<endl;

	//这个队列q1是int类型,输入遇到其他类型的元素,会强制转换为int
	Queue<int> q1;
	double a = 6.66;
	q1.push(1);
	q1.push(a);
	q1.push(3);
	
	cout << "q1:" << q1;

	//构造一个队列q2 怎么构造:拷贝已有的整段Queue q1
	Queue<int> q2(q1);
	cout << "q2:" << q2;

	//拷贝整段队列q3,加在原有的队列q2后,但不能自己拷贝自己
	Queue<int> q3;
	q3.push(1);
	q3.push(2);
	q3.push(3);
	cout << "q3:" << q3;
	q2.copy_items(q3);
	cout << "q2:" << q2;

	//构造一个队列q4 怎么构造:切片拷贝已有数组
	double num[8] = { 1.1,2.2,-3.3,4.4,-5.5,6.66 };
	Queue<double> q4(num, num + 8);
	cout << "q4:" << q4;

	//切片拷贝,加在原有的队列q2、q4后
	q2.copy_items(num, num + 6);
	q4.copy_items(num+1, num + 5);
	cout << "q2:" << q2;
	cout << "q4:" << q4;

	//切片拷贝,回删原有队列
	q4.assign(num + 1, num + 6);
	cout << "q4:" << q4;

	//重载后的赋值运算符
	Queue<double> q5(num, num + 1);
	q4 = q5;
	cout << "q5:" << q5;
	cout << "q4:" << q4;

	//QueueItem<double>* c = q5.End();
	//cout << c;


	return 0;

}

输出:

q1:[1 6 3 ]
q2:[1 6 3 ]
q3:[1 2 3 ]
q2:[1 6 3 1 2 3 ]
q4:[1.1 2.2 -3.3 4.4 -5.5 6.66 0 0 ]
q2:[1 6 3 1 2 3 1 2 -3 4 -5 6 ]
q4:[1.1 2.2 -3.3 4.4 -5.5 6.66 0 0 2.2 -3.3 4.4 -5.5 ]
q4:[2.2 -3.3 4.4 -5.5 6.66 ]
q5:[1.1 ]
q4:[1.1 ]

模板特化

我们来看一个不理想的结果:

mian.cpp

	Queue<const char*> qst;
	char str[10];
	strcpy(str, "I'm");
	qst.push(str);
	strcpy(str, "Hanyan");
	qst.push(str);
	strcpy(str, "Wei");
	qst.push(str);
	cout << qst;

在使用strcpy()函数时会报错函数存在隐藏危险,只需要在在预处理定义中添加:_CRT_SECURE_NO_WARNINGS

输出:

[Wei Wei Wei ]

这并不是我们想要的结果,因为我们Queue里面存的是str的指针 而最后的str存的是Wei 所以qst存的也一直是Wei,对于类模板的push操作,一般的非指针类型,push方法会自动开辟一个新的空间,因此不必考虑地址重合的问题,但是,这个Queue存的是一个指针类型,就出现了问题。

模板成员函数特化

Queue里存的始终都是str最初的地址空间,因此对于这种指针类型的元素,我们需要对push函数进行模板成员函数特化处理:

template<>
void Queue<const char*>::push(const char* const& val) 
{
	//创建元素为val的实列块
	//这里本来存的const char*指针
	//QueueItem<const char*>* pt = new QueueItem<const char*>(val);
	//但是我们现在想要的是指针所指向的字符串,那我们就需要为每次指针指向的字符串申请新空间
	char* pData = new char[strlen(val) + 1];
	//然后把每次指针所指向的字符串复制到申请新空间
	strcpy(pData, val);
	//存它
	QueueItem<const char*>* pt = new QueueItem<const char*>(pData);
	//若队列为空,则新进入的实例块既是头指针也是尾指针
	if (empty()) {
		head = tail = pt;
	}
	else {
		//新进入的实例块放在尾指针后,尾指针指向它
		tail->next = pt;
		tail = pt;
	}
	
}

template<>
void Queue<const char*>::pop()
{
	//先进先出
	//找到头指针
	QueueItem<const char*>* p = head;
	head = head->next;
	//因为现在不仅存了指针,还另外申请空间存字符串,所以也要另外删除
	delete[]p->item;
	//删除p
	delete p;
}

同样的,这需要在main.cpp中实现

输出:

[I'm Hanyan Wei ]

是我们想要的结果。

类模板特化

这是另外的一种方法——类模板Queue的全特化:实际储存的不是cosnt char*指针,而是string类型:

template<>
class Queue<const char*>
{
public:
	//进队
	void push(const char* const& val) 
	{
		//push函数会把 const char* 类型强制转换为string
		real_que.push(val);
	}

	//出队
	void pop()
	{
		real_que.pop();
	}

	//判断队列是否为空
	bool empty()const
	{
		return real_que.empty();
	}

	//获取头指针的元素
	const string & front() const { return real_que.front(); }

	//重载输出运算符
	friend ostream& operator<<(ostream& os, const Queue<const char*>& q)
	{
		//输出const char* 队列的成员变量real_que
		os << q.real_que;
		return os;
	}

private:

	//实际存储的数据类型是string
	Queue<string> real_que;
	
};

同样的,这需要在main.cpp中实现

输出:

[I'm Hanyan Wei ]

是我们想要的结果。

三、智能指针(模板类AutoPtr)

        我们知道除了静态内存和栈内存外,每个程序还有一个内存池,这部分内存被称为自由空间或者堆。程序用堆来存储动态分配的对象即那些在程序运行时分配的对象,当动态对象不再使用时,我们的代码必须显式的销毁它们;所以,动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。为了更加容易(更加安全)的使用动态内存,引入了智能指针的概念。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象;它能自动判别所指向的内存是否还有常规指针指向它,如果没有,则表示该片内存的生命周期已结束,该片内存自动释放。

其中,有三种智能指针类型:

  1. shared_ptr:允许多个指针指向同一个对象
  2. unique_ptr:“独占”所指向的对象
  3. weak_ptr:它是一种弱引用,指向shared_ptr所管理的对象,与shared_ptr同用,不影响对象生命周期

智能指针会有一个计数器用来代表当前“用户数”也就是判断当前地址是否有常规指针指向它,但”用户数“为0时,这块地址就要被释放了

用一个模板类AutoPtr实例来了解一下智能指针:

构造函数

//指针构造器 初始化为指向pData
template<class T>
AutoPtr<T>::AutoPtr(T* pData)
{
	//new一个ptr指针初始化为指向pData
	ptr = pData;
	//new一个user初始化为1
	user = new int(1);
}

拷贝构造函数

//指针拷贝构造器 怎么构造:拷贝已有的AutoPtr
template<class T>
AutoPtr<T>::AutoPtr(const AutoPtr<T>& handle)
{
	//ptr初始化为指向handle数据的指针
	ptr = handle.ptr;
	//user初始化为指向handle用户数的指针
	user = handle.user;
	(*user)++;
}

析构函数

//析构函数 如果自己释放了,那自己指向的数据地址的当前地址的指针以及用户数减一
template<class T>
AutoPtr<T>::~AutoPtr()
{
	cout << "智能指针" << this << "已销毁" << endl;
	decr();
}

赋值运算符重载

//当前地址的指针以及用户数减一
template<class T>
void AutoPtr<T>::decr()
{
	//用户数减一
	(*user)--;
	if ((*user) == 0) {
		delete ptr;
		//ptr地址赋为空
		ptr = 0;
		delete user;
		//user地址赋为空
		user = 0;
		cout << "智能指针" << this << "原先指向的地址已经没有指针指向它了 该地址内存释放" << endl;
	}
}

//重载赋值运算符 表示指针改指为handle这个数据
template<class T>
AutoPtr<T>& AutoPtr<T>:: operator=(const AutoPtr<T>& handle) 
{
	//如果handle是本身 则返回本身
	if (this == &handle) return *this;
	//ptr指向的原数据地址的指针以及用户数减一 
	decr();
	//ptr改为指向handle数据的指针
	ptr = handle.ptr;
	//user改为指向handle用户数的指针
	user = handle.user;
	(*user)++;
	return *this;
}

->、*等运算符重载

//重载-> 返回指针 代表对智能指针指向的原始数据进行操作,而不是操作智能指针本身
template<class T>
T*  AutoPtr<T>::operator->()
{
	return ptr;
}

//重载* 返回指针所指的对象 代表对智能指针所指的对象里的数据进行操作,而不是操作对象
template<class T>
T& AutoPtr<T>::operator*() 
{ 
	return *ptr; 
}

完整AutoPtr.h

#ifndef AUTOPRT_H
#define AUTOPRT_H
#include<iostream>
using namespace std;


template<class T>
class AutoPtr 
{
public:

	//指针构造器 初始化为指向pData
	AutoPtr(T* pData);

	//指针拷贝构造器 怎么构造:拷贝已有的AutoPtr
	AutoPtr(const AutoPtr<T>& handle);

	//重载赋值运算符 表示指针改指为handle这个数据
	AutoPtr<T>& operator=(const AutoPtr<T>& handle);

	//当前地址的指针以及用户数减一
	void decr();

	//析构函数 如果自己释放了,那自己指向的数据地址的当前地址的指针以及用户数减一
	~AutoPtr();

	//重载-> 返回指针 代表对智能指针指向的对象进行操作,而不是操作智能指针本身
	T* operator->();
	const T* operator->() const { return ptr; }

	//重载* 返回指针所指的对象 代表对智能指针所指的对象里的数据进行操作,而不是操作对象
	T& operator*();
	const T& operator*() const { return *ptr; }

private:
	//指向储存数据的指针
	T* ptr;
	//用户数 带*代表这个user是统一指向存储用户数的地址,保证了用户数的统一修改
	int* user;
};

//指针构造器 初始化为指向pData
template<class T>
AutoPtr<T>::AutoPtr(T* pData)
{
	//new一个ptr指针初始化为指向pData
	ptr = pData;
	//new一个user初始化为1
	user = new int(1);
}

//指针拷贝构造器 怎么构造:拷贝已有的AutoPtr
template<class T>
AutoPtr<T>::AutoPtr(const AutoPtr<T>& handle)
{
	//ptr初始化为指向handle数据的指针
	ptr = handle.ptr;
	//user初始化为指向handle用户数的指针
	user = handle.user;
	(*user)++;
}

//当前地址的指针以及用户数减一
template<class T>
void AutoPtr<T>::decr()
{
	//用户数减一
	(*user)--;
	if ((*user) == 0) {
		delete ptr;
		//ptr地址赋为空
		ptr = 0;
		delete user;
		//user地址赋为空
		user = 0;
		cout << "智能指针" << this << "原先指向的地址已经没有指针指向它了 该地址内存释放" << endl;
	}
}

//重载赋值运算符 表示指针改指为handle这个数据
template<class T>
AutoPtr<T>& AutoPtr<T>:: operator=(const AutoPtr<T>& handle) 
{
	//如果handle是本身 则返回本身
	if (this == &handle) return *this;
	//ptr指向的原数据地址的指针以及用户数减一 
	decr();
	//ptr改为指向handle数据的指针
	ptr = handle.ptr;
	//user改为指向handle用户数的指针
	user = handle.user;
	(*user)++;
	return *this;
}

//析构函数 如果自己释放了,那自己指向的数据地址的当前地址的指针以及用户数减一
template<class T>
AutoPtr<T>::~AutoPtr()
{
	cout << "智能指针" << this << "已销毁" << endl;
	decr();
}

//重载-> 返回指针 代表对智能指针指向的原始数据进行操作,而不是操作智能指针本身
template<class T>
T*  AutoPtr<T>::operator->()
{
	return ptr;
}

//重载* 返回指针所指的对象 代表对智能指针所指的对象里的数据进行操作,而不是操作对象
template<class T>
T& AutoPtr<T>::operator*() 
{ 
	return *ptr; 
}

#endif // !AUTOPRT_H

main.cpp

	//指针构造器 新建一个智能指针h1 指向一个CMatrix对象
	AutoPtr<CMatrix> h1(new CMatrix);
	AutoPtr<CMatrix> h2(new CMatrix);
	AutoPtr<CMatrix> h3(new CMatrix);
	cout << "h1:" << &h1 << endl;
	cout << "h2:" << &h2 << endl;
	cout << "h3:" << &h3 << endl;

	//拷贝指针构造器 新建一个智能指针h2 指向h1指向的CMatrix对象
	AutoPtr<CMatrix> h4(h1);
	cout << "h4:" <<  &h4 << endl;

	cout << "=========================" << endl;
	
	double data1[6] = { 1,2,3,4,5,6 };
	double data2[6] = { 7,8,9,10,11,12 };
	double data3[2] = { 7,8 };
	//h1->重载后代表h1智能指针指向的对象 
	h1->Create(2, 3, data1);
	h2->Create(2, 3, data2);
	h3->Create(1, 2, data3);
	cout << "h1: " << *h1 << endl;
	cout << "h2: " << *h2 << endl;
	cout << "h3: " << *h3 << endl;
    cout << "h4: " << *h4 << endl;

	cout << "=========================" << endl;
	
	//*h4代表h4指向的地址所存的对象的数据 因为h1和h4指向的是统一内存地址 所以h4指向的对象也是h1所指的对象
	(*h4).Set(0, 1, 10);
	cout << "h1: " << *h1 << endl;
	cout << "h2: " << *h2 << endl;
	cout << "h3: " << *h3 << endl;
	cout << "h4: " << *h4 << endl;

	cout << "=========================" << endl;

	//把h1指向的内存地址赋给h3 h3就指向了h1的指向 h3原先指向的内存地址就没有指针指向了 所以会出现释放内存
	h3 = h1;
	h1 = h2;
	cout << "h1: " << *h1 << endl;
	cout << "h2: " << *h2 << endl;
	cout << "h3: " << *h3 << endl;
	cout << "h4: " << *h4 << endl;
	cout << "--------------------------------" << endl;

输出:

h1:00DEFE14
h2:00DEFE04
h3:00DEFDF4
h4:00DEFDE4
=========================
h1: 2 3
1 2 3
4 5 6

h2: 2 3
7 8 9
10 11 12

h3: 1 2
7 8

h4: 2 3
1 2 3
4 5 6

=========================
h1: 2 3
1 10 3
4 5 6

h2: 2 3
7 8 9
10 11 12

h3: 1 2
7 8

h4: 2 3
1 10 3
4 5 6

=========================
智能指针00DEFDF4原先指向的地址已经没有指针指向它了 该地址内存释放
h1: 2 3
7 8 9
10 11 12

h2: 2 3
7 8 9
10 11 12

h3: 2 3
1 10 3
4 5 6

h4: 2 3
1 10 3
4 5 6

--------------------------------
智能指针00DEFDE4已销毁
智能指针00DEFDF4已销毁
智能指针00DEFDF4原先指向的地址已经没有指针指向它了 该地址内存释放
智能指针00DEFE04已销毁
智能指针00DEFE14已销毁
智能指针00DEFE14原先指向的地址已经没有指针指向它了 该地址内存释放

让我来解释一下这个输出是怎么回事:

下面一段对应输出的第一段h1h2h3分别指向三片不同的内存地址,由拷贝指针构造函数构造出的h4拷贝于h1,所以h1h4指向同一片内存地址。

    //指针构造器 新建一个智能指针h1 指向一个CMatrix对象
    AutoPtr<CMatrix> h1(new CMatrix);
    AutoPtr<CMatrix> h2(new CMatrix);
    AutoPtr<CMatrix> h3(new CMatrix);
    cout << "h1:" << &h1 << endl;
    cout << "h2:" << &h2 << endl;
    cout << "h3:" << &h3 << endl;

    //拷贝指针构造器 新建一个智能指针h2 指向h1指向的CMatrix对象
    AutoPtr<CMatrix> h4(h1);
    cout << "h4:" <<  &h4 << endl;

下面一段对应输出的第二段、第三段,主要操作是,对h4指向的对象的数据进行修改,由于h1h4指向同一片内存地址,所以对h4指向的对象的数据进行修改就是所以对h1指向的对象的数据进行修改。

    double data1[6] = { 1,2,3,4,5,6 };
    double data2[6] = { 7,8,9,10,11,12 };
    double data3[2] = { 7,8 };
    //h1->重载后代表h1智能指针指向的对象
    h1->Create(2, 3, data1);
    h2->Create(2, 3, data2);
    h3->Create(1, 2, data3);
    cout << "h1: " << *h1 << endl;
    cout << "h2: " << *h2 << endl;
    cout << "h3: " << *h3 << endl;
    cout << "h4: " << *h4 << endl;

    cout << "=========================" << endl;
    
    //*h4代表h4指向的地址所存的对象的数据 因为h1和h4指向的是统一内存地址 所以h4指向的对象也是h1所指的对象
    (*h4).Set(0, 1, 10);
    cout << "h1: " << *h1 << endl;
    cout << "h2: " << *h2 << endl;
    cout << "h3: " << *h3 << endl;
    cout << "h4: " << *h4 << endl;

    cout << "=========================" << endl;

 下面一段对应输出的第四段,主要操作就是让h3指向h1和h4指向的那片内存地址,h3原先指向的内存地址就没有指针指向了,那片内存地址释放内存;再让h1指向h2指向的那片内存地址,所以最后的输出h1和h2一样,h3和h4一样:


    //把h1指向的内存地址赋给h3 h3就指向了h1的指向 h3原先指向的内存地址就没有指针指向了 所以会出现释放内存
    h3 = h1;
    h1 = h2;
    cout << "h1: " << *h1 << endl;
    cout << "h2: " << *h2 << endl;
    cout << "h3: " << *h3 << endl;
    cout << "h4: " << *h4 << endl;
    cout << "--------------------------------" << endl;

最后那段输出就是智能指针的智能之处,程序结束:h3、h4指针销毁,h3、h4原先指向的内存地址就没有指针指向了,那片内存地址释放内存;h1、h2指针销毁,h1、h2原先指向的内存地址就没有指针指向了,那片内存地址释放内存。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值