提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录- 前言
- 一、pandas是什么?
- 二、使用步骤
- 1.引入库
- 2.读入数据
- 总结
前言
本次实验将实现模板类,模板函数,模板函数特化,智能指针的设计,并对其进行相应测试。
一、实验内容
一、模板函数(compare)
1.一般模板函数
2.特化模板函数
二、类模板Queue
1.类模板(Queue)
2.成员模板函数
3.模板特化:模板函数特化、模板成员函数特化、模板类特化
三、模板类AutoPtr
1.构造函数
2.析构函数
3.拷贝构造函数
4.等号、->、*等运算符重载
5.6主函数调用AutoPtr
二、实验过程
1.模板函数
int compare(int a,int b)
{
return a>b? a:b;
}
double compare(double a,double b)
{
return a>b? a:b;
}
这两个函数都是用来判断a和b的大小,只有参数类型不同,功能完全一样,类似这种的情况,如果能写一段通用代码适用于多种不同数据类型,便会使代码的可重用性大大提高,从而提高软件的开发效率。使用模板函数就是为了这一目的。只需对模板函数编写一次,然后基于调用函数时提供的参数类型,C++编译器将自动产生相应的函数来正确的处理该类型的数据。
函数模板的定义形式:
template<模板参数表>
类型名 函数名(参数表)
{
函数体的定义
}
1.1 一般模板函数
template//class关键字表明T是一个类型,在模板定义中class和typename作用相同 int compare(const T &a,const T &b) { //使用模板函数,函数的传入参数类型必须相同,即不能一个int,一个double if(a>b) return 1; else if(a>a>>b; cout<<"result is:"; cout< 注:1.函数模板本身在编译时不会生成任何目标代码,只有由模板生成的实例会生成目标代码;
2.被多个源文件引用的函数模板,应当连同函数体一同放在头文件中,而不能像普通函数一样只将声明放在头文件中;
3.函数指针也只能指向模板的实例,而不能指向模板本身。
运行结果:
1.1 特化模板函数template<> int compare(const char * const &v1, const char * const &v2) { return strcmp(v1,v2); //比较两个字符串 //根据比较结果返回一个int类型的值。如果返回值小于0,则表示在ASCII码表上v1字符串小于v2字符串 } void testCompare() { const char *v1 = "hello"; //或const char * const v1 = "hello"; //与指针指向的数据类型是const有关还是非const有关,而与指针是const还是非const无关 const char *v2 = "world"; cout< 注:1.compare后指定特化时的模板形参即const char *类型,就是说在以实参类型const char * 调用函数时,将产生该模板的特化版本。
2.形参“const char * const &v1”去掉修饰符const,实际类型是char * &v1,也就是v1是一个引用,一个指向char型指针的引用,即指针的引用,加上const,v1 就是一个指向const char 型指针的const引用;所以不能用一个指向非const 数据的指针调用特化版本,因为数据类型不匹配。
3.由于compare
声明的形参都是const char *,即char *型指针存储的是const 数据,所以不能传递一个存储了非const数据的char *型指针。同时由于编译器对特化版本不进行实参形参的常规转换,所以调用的实参必须与特化版本的声明完全一致,否则将从泛型(一般型)版本进行实例化,或者函数匹配错误。 4.被特化的函数模板,无论是否被调用,相关的目标代码都会生成,因此他们的定义放在源文件(.cpp)中,而非头文件中。
运行结果:
2.类模板(Queue) 2.1 类模板使用模板类可以使用户为类定义一种模式,使得类中的某些数据成员、某些成员函数的参数、返回值或局部变量能取不同类型(包括系统预定义和用户自定义的)。
类模板声明的语法形式:
template <模板参数表> class 类名 { 类成员声明 {定义一个类模板Queue和管理类QueueItem,实现向队列中增加元素,删除元素等操作。
template//Type表示通用数据类型,即可以取任意返回值 class Queue; template //类模板的定义,类模板的使用实际上是将类模板实例化成一个具体的类 class QueueItem { Type item; QueueItem * next; QueueItem(const Type& val):item(val),next(NULL){} //参数列表构造器方法 friend Queue ; //将队列定义为友元类,方便访问私有变量 friend ostream& operator<<(ostream &os,const Queue &que); public: QueueItem * operator++() { return next; //返回队列下一个元素的指针 } Type & operator*() //取出存储的元素 { return item; } }; template class Queue { public: Queue(); Queue(const Queue &q); ~Queue(); bool isEmpty(); //判断队列是否为空 void Push(const Type& val); //在队列里面增加元素 void Pop(); //在队列里面删除元素 void destroy(); //清空队列 Type& front(); //输出队列中的第一个元素 void copy_item(const Queue &orig); //拷贝全部队列 template //成员模板函数 Queue(It beg,It end); //新的有参构造函数 template void assign(It beg,It end); //向队列中添加指定数据 template void copy_items(It beg,It end); //拷贝部分队列 //访问头部和尾部的函数 const QueueItem * Head() const{return head;} const QueueItem * End() const{return(tail==NULL)? NULL:tail;} private: QueueItem * head; //队列头指针 QueueItem * tail; //队列尾指针,使用含有模板类组成的QueueItem类需要使用模板声明 friend ostream& operator<<(ostream &os,const Queue &que) { os<<"< "; for(QueueItem * p = que.head;p!=NULL;p=p->next) { os< item<<" "; } os<<">"; return os; } }; 一个类模板声明自身并不是一个类,只有当被其他代码引用时,模板才根据引用的需要生成具体的类,即类模板的使用-----实例化成一个具体的类
2.2 成员模板函数的实现定义的语法格式:
template <模板参数表> 类型名 类名<模板参数标识符列表>::函数名(参数表)成员模板函数同样要写在.h文件里
templateQueue ::Queue():head(NULL),tail(NULL) //指针必须初始化 { } template Queue ::Queue(const Queue &q):head(NULL),tail(NULL) { copy_items(q); //拷贝构造器 } template Queue ::~Queue() { destroy(); cout<<"delete Queue"< void Queue ::copy_item(const Queue &orig) //拷贝全部队列 { for(QueueItem *pt = orig.head;pt!=NULL;pt=pt->next) { push(pt->item); } //将队列orig的所有元素插入其他队列,原队列仍然保留 } template bool Queue ::isEmpty() { if(head==NULL) return true; else return false; } template void Queue ::Push(const Type& val) { QueueItem * pt = new QueueItem (val); if(isEmpty()) { head = tail = pt; } else { tail->next = pt; tail = pt; } } template void Queue ::Pop() { QueueItem * p = head; head = head->next; delete p; //释放空间 } template Type& Queue ::front() { Type ans = 0; if(!isEmpty()) { return head->item; } else { cout<<" Queue is NULL!"< void Queue ::destroy() { while (!isEmpty()) { Pop(); } head = tail =NULL; } template template Queue ::Queue(It beg,It end):head(NULL),tail(NULL) { copy_items(beg,end); } template template void Queue ::assign(It beg,It end) { destroy(); copy_items(beg,end); } template template void Queue ::copy_items(It beg,It end) { for(It it=beg;it!=end;it++) { Push(*it); } } 对编写的类模板和其成员函数进行测试:
void testQueue() { //Queueqt; //为什么用int输出是10,4,20;double输出是10,4.4,20 //因为定义的对象的真实数据类型是int,所以会进行强制类型转换,输出的是4 //类模板定义对象:类模板名<真实数据类型> 对象名; Queue qt; double c=4.4; qt.Push(10); qt.Push(c); qt.Push(20); cout< qt1(data,data+5); cout< vi(data,data+5); //数组 qt1.assign(vi.begin()+1,vi.end()-1); //列表中添加3,6,9 cout< 运行结果:
2.3 模板函数特化当我们所写的模板无法适应所有数据类型时,就需要对部分函数进行特化,为了能输出想要的字符串结果,对字符串数据进行特化
//争对const char*数据类型对Push()函数进行特化 template<> void Queue2.4 模板类的特化::Push(const char * const &val) { char* new_item = new char[strlen(val)+1]; //根据字符串长度进行创建字符数组 strncpy(new_item,val,strlen(val)+1); //拷贝字符串内容 QueueItem * pt = new QueueItem (new_item); if(isEmpty()) { head=tail=pt; } else{ tail->next = pt; tail = pt; } } 对Pop()函数进行特化 template<> void Queue ::Pop() { QueueItem * p = head; //特化模板类QueueItem delete head->item; //释放char *数据 head = head->next; delete p; //释放指针空间 } 针对const char*数据类型对类模板Queue实现特化
template<> class Queue//针对const char*数据类型对Queue实现特化 { public: void Push(const char* const &val) { //real_que.Push(val); //会先进行类型转换,将const char*转成string类型 //第一种特化 char* new_item = new char[strlen(val)+1]; //根据字符串长度进行创建字符数组 strncpy(new_item,val,strlen(val)+1); //拷贝字符串内容 QueueItem * pt = new QueueItem (new_item); if(isEmpty()) { head=tail=pt; } else{ tail->next = pt; tail = pt; } } void Pop() { //real_que.Pop(); QueueItem * p = head; //特化模板类QueueItem delete head->item; //释放char *数据 head = head->next; delete p; //释放指针空间 } void destroy() { while (!isEmpty()) { Pop(); } head = tail =NULL; } bool isEmpty() const { if(head==NULL) return true; else return false; } string & front() { return real_que.front(); } void copy_item(const Queue &orig); friend ostream & operator<<(ostream& os,Queue &que) { os< real_que; QueueItem *head; QueueItem *tail; }; 测试特化类和特化函数:
void testQueue1() { Queueqst; qst.Push("I am"); qst.Push("Ren"); qst.Push("Ruijie"); cout< 运行结果:
3.智能指针 3.1 智能指针的创建智能指针的作用是管理一个指针,因为存在以下这种情况:申请的空间在函数结束时忘记释放,造成内存泄漏。使用智能指针可以很大程度上的避免这个问题,因为智能指针是一个类,当超出了类的实例对象的作用域时,会自动调用对象的析构函数,析构函数会自动释放资源。所以智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。
对一个对象进行初始化时不能将一个普通指针直接赋值给智能指针,因为一个是指针,一个是类。可以通过构造函数传入普通指针。
3.2 测试智能指针
总结提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。



