模板

模板是泛型编程的基础,即与类型无关的逻辑代码。

利用模板机制可以显著减少冗余信息,能大幅度地节约程序代码,进一步提高面向对象程序的可重用性和可维护性。

模板是实现代码重用机制的一种工具,它可以实现类型参数化;

模板分为函数模板和类模板。

为了使用函数名相同,参数不同,返回值可同可不同的函数时,我们起初用了重载的方式。

#include<iostream>
using namespace std;int add(int a,int b)
{return a+b;
}double add(double a,double b)
{return a+b;
}int main()
{cout<<"ret1="<<add(1,2)<<endl;cout<<"ret2="<<add(2.3,3.0)<<endl;getchar();return 0;
}

wKioL1bvstuDo-moAAAPLD_E0cI751.png

但是运用重载的方式写起来比较不方便,尤其是重载的函数较多时,为了解决这类问题,我们用函数模板来实现这种功能。

#include<iostream>
using namespace std;
template <class T>
T add(const T& a,const T& b)
{cout<<"type:"<<typeid(a).name()<<endl;   //显示类型return a+b;
}int main()
{cout<<"ret1="<<add(1,2)<<endl;//还可以显示实例化,显示指定T为int,即add<int>(1,2)cout<<"ret2="<<add(2.3,3.0)<<endl;   //add<double>(2.3,3.0)getchar();return 0;
}

wKioL1bvt4bxX-QPAAARBJCMVr0319.png

以上函数中函数参数类型都是相同的,当我们遇到形如:add(1,2.3);一个参数为int,一个参数为double型,此时我们可以这样定义:

template <class T1,class T2>
T add(const T1& a,const T2& b)
{return a+b;
}

当然,肯定有人会想,模板函数可以构成重载吗?    j_0057.gif答案是肯定的。

#include<iostream>
using namespace std;int add(int a,int b)
{return a+b;
}double add(double a,double b)
{return a+b;
}
template <class T>
T add(const T& a,const T& b)
{cout<<"type:"<<typeid(a).name()<<endl; return a+b;
}int main()
{cout<<"ret1="<<add(1,2)<<endl;cout<<"ret2="<<add(2.3,3.0)<<endl;getchar();return 0;
}

当模板构成重载,调用add的函数时,它会先调用非模板类的函数,性能比较高;而模板函数内部还得调用,有推演过程判断它是什么类型,效率上会有所降低。


2.模板类

对于普通函数来说,我们拿typedef重定义一个类型,当需要改的时候,需要将int改掉就可以了;

typedef int DataType;class SEQLIST
{
private:DataType *data;
};

而我们为了适应更多的类型,于是引入了模板类,我们这样定义,体现了其高度复用的优势:

template<class T>
class SeqList
{
private:T* data;
};

写一个模板类实现SeqList的动态顺序表吧:

#include<iostream>
using namespace std;template <class T>
class SeqList
{
public:SeqList():_data(NULL),_size(0),_capacity(0){}SeqList(const SeqList<T>& s);SeqList<T>& operator=(const SeqList<T>& s);~SeqList(){if(_data != NULL){delete[] _data;}}void CheckCapacity();void PushBack(const T& d);void PopBack();void PushFront(const T& d);void PopFront();void Print();
private:T *_data;int _size;int _capacity;
};
template <class T>
SeqList<T>::SeqList(const SeqList<T>& s)
{_data = new T[s._size*sizeof(T)];int i = 0;for(i = 0;i < s._size; i++){_data[i] = s._data[i];}_size = s._size;_capacity = s._capacity;
}
template <class T>
SeqList<T>& SeqList<T>::operator=(const SeqList<T>& s)
{int i = 0;if(this == &s){return *this;}_size = s._size;_capacity = s._capacity;delete _data;_data = new T[_capacity];for(i = 0; i < _size; i++){_data[i] = s._data[i];}return *this;
}
template <class T>
void SeqList<T>::CheckCapacity()
{if(_size == _capacity){T* tmp = new T[_capacity*2+3];//memcpy(tmp,_data,_size*sizeof(T));int i = 0;for(i = 0; i < _size; i++){tmp[i] = _data[i];}delete[] _data;_data = tmp;_capacity = _capacity*2+3;}
}
template <class T>
void SeqList<T>::PushBack(const T& d)
{CheckCapacity();_data[_size] = d;_size++;
}
template <class T>
void SeqList<T>::PopBack()
{CheckCapacity();_size--;
}template <class T>	
void SeqList<T>::PushFront(const T& d)
{int i ;CheckCapacity();	for(i = _size; i > 0; i--){_data[i] = _data[i-1];}_data[0] = d;_size++;
}template <class T>
void SeqList<T>::PopFront()
{int i;CheckCapacity();for(i = 0; i < _size; i++){_data[i] = _data[i+1];}_size--;
}
template <class T>
void SeqList<T>::Print()
{int i = 0;for(i = 0; i < _size; i++){cout<<_data[i]<<" ";}cout<<endl;
}int main()
{SeqList<int> seq;SeqList<int> seq1;cout<<"seq:"<<endl;cout<<"尾插1234"<<endl;seq.PushBack(1);seq.PushBack(2);seq.PushBack(3);seq.PushBack(4);seq.Print();cout<<"尾删"<<endl;seq.PopBack();seq.Print();cout<<"头删"<<endl;seq.PopFront();seq.Print();cout<<"seq2:"<<endl;SeqList<int> seq2(seq);seq2.Print();cout<<"头插567"<<endl;seq.PushFront(5);seq.PushFront(6);seq.PushFront(7);seq.Print();seq1 = seq;cout<<"seq1:"<<endl;seq1.Print();getchar();return 0;
}

wKiom1byIpvxh_K5AAAVEIOLwCM902.png

模板就说到这里啦,有好的建议还希望大家提出来,欢迎来访哦。i_f01.gifi_f01.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382884.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux-----强大的find

我又回来了。哈哈。今天我们来说一下linux中的另一个强大的find命令&#xff0c;灰常重要&#xff0c;灰常重要&#xff0c;灰常重要。显而易见&#xff0c;find就是对某一个文件或者目录的查找喽。但是它的一个显著的特点就是&#xff1a;一般放在后台执行&#xff0c;从整个文…

C语言模拟实现标准库函数之strcmp()

strcmp() C/C函数&#xff0c;比较两个字符串 设这两个字符串为str1&#xff0c;str2&#xff0c; 若str1str2&#xff0c;则返回零&#xff1b; 若str1<str2&#xff0c;则返回负数&#xff1b; 若str1>str2&#xff0c;则返回正数。 char * my_strcmp(char *key,…

linux之task_struct

每个进程中都有一个进程控制块--PCB。PCB--维护进程相关的信息。然而&#xff0c;linux内核的进程控制块就是task_struct结构体&#xff0c;它可以保存进程的信息。 所有运行在系统里的进程都以task_struct链表的形式存在内核里。 每个进程都将它的信息放在task_struct结构体…

C语言模拟实现标准库函数之memcpy()

memcpy&#xff08;&#xff09; 1.如果我们需要对一个数组初始化&#xff0c;把数组的内容全部置0&#xff0c;那么能不能用strcpy() int main() {char arr1[10] { 0 };char arr2[10] " abcdefg ";strcpy(arr2, arr1);system("pause");return 0; } 我…

说说堆及堆排序

堆&#xff1a;是一种数组对象&#xff0c;它可以被看成是一种二叉树结构。 我们把堆的二叉树存储方式分为两种&#xff1a;即大堆和小堆。那么问题来了&#xff0c;什么大堆&#xff1f;什么是小堆&#xff1f; 大堆&#xff1a;让每个父节点的值都大于孩子节点的值。 小堆…

linux之父子进程的输出

首先&#xff0c;我们来回忆一下父进程与子进程&#xff0c;前几节讲了如何创建子进程&#xff0c;像这样的&#xff0c;pid_t id fork(); 这样我们就创建好了一个子进程&#xff0c;然而fork()函数的返回值是什么呢&#xff1f;这里要记住&#xff1a;子进程返回0&#xff0c…

linux---谈谈vfork和fork的区别及exit与return

fork()&#xff1a;创建子进程的函数&#xff0c;是大家比较熟悉的吧。pid_t id fork(); 这里的vfork();也是创建子进程的函数。现在我们来剖析一下它们吧。 第一例&#xff1a; 先看一个fork()的例子哦。 对于fork()而言&#xff0c;创建子进程成功后直接打印出父子进程执…

C语言模拟实现标准库函数之qsort()

qsort 编译器函数库自带的快速排序函数。 void qsort(void*base,size_t num,size_t width,int(__cdecl*compare)(const void*,const void*)); 参数解释&#xff1a; void*base-待排序数组首地址size_t num-数组中待排序元素数量size_t width-各元素的占用空间大小int(__cde…

linux之管道

管道&#xff08;PIPE&#xff09;是linux中一个重要的通信方式&#xff0c;在进程中&#xff0c;我们通过从一个进程中读取到的数据转到另一个进程中的写数据中&#xff0c;这时就要有不同的进程之间共享同一份资源&#xff0c;就是所谓的进程间通信。由于进程的特点是资源独占…

linux之多线程(1)

我们之前讲了进程&#xff0c;今天我们重新认识另外一个概念---线程。我们首先会想到的是进程和线程有什么区别和联系&#xff0c;对吧&#xff1f;进程是由程序执行起来&#xff0c;跑在操作系统的&#xff0c;是系统进行资源分配和调度的基本单位。进程具有资源独占性&#x…

linux之睡眠函数(my_sleep)

我们在程序中&#xff0c;很多次用到sleep()函数&#xff0c;让它睡眠几秒后再执行该进程。今天呢&#xff0c;我要给大家实现一下sleep函数。 看看代码哦&#xff1a; 运行结果&#xff1a; 结果中每隔三秒钟&#xff0c;打印一条语句。实现了sleep(3)的功能。 关于sleep函数…

C语言 防止头文件被多次引用

comm.h和comm.c是公共模块。 test1.h和test1.c使用了公共模块。 test2.h和test2.c使用了了公共模块。 test.h和test.c使⽤用了了test1模块和test2模块。 这样最终程序中就会出现两份comm.h的内容。这样就造成了了文件内容的重复。 1.方法1 文件开头加上这一句就ok #prag…

详解强制类型转换

今天谈谈类型转换的问题吧&#xff0c;之前我们也遇到过类型转换&#xff0c;比如c语言中这样的赋值&#xff1a; 显然&#xff0c;i和j是不同类型的变量&#xff0c;但是却可以完成赋值&#xff0c;结果是这样的&#xff1a; 其实它们是做了隐式的类型转换&#xff0c;相当于&…

c++之类型萃取

刚刚我们接触过模板类&#xff0c;类似于这样的&#xff1a; 在这个类中&#xff0c;我们如何知道它是什么类型的呢&#xff1f;这里&#xff0c;我们可以在类中加入一个内嵌类型&#xff0c;如&#xff1a; 这样就可以知道它是用户自定义的还是本身类型就拥有的&#xff0c;我…

时间复杂度空间复杂度

我们编过不少代码&#xff0c;起初学习的时候我们习惯性的认为&#xff0c;只要代码能正确的运行就ok啦~很少考虑代码的优化带来的好处。今天说一下影响代码性能的两个重要指标--时间复杂度&空间复杂度。 时间复杂度&#xff1a;就是函数&#xff08;指数学中的函数&#…

C语言 函数递归例题解析

1.接受一个整形值&#xff08;无符号&#xff09;&#xff0c;把它转换为 字符并打印它模拟实现strlen()函数。3.求n的阶乘4.斐波那契数列总结 1.接受一个整形值&#xff08;无符号&#xff09;&#xff0c;把它转换为 字符并打印它 void fun(int x) {if (x > 9){fun(x/10)…

剖析printf函数

printf是什么&#xff0c;对于起初学习c语言的同学来说肯定都特别的疑惑。在这里&#xff0c;解答一下&#xff1a;它是一个函数。既然是一个函数的话&#xff0c;想必肯定有返回值和参数吧。那么它的返回值和参数是什么呢&#xff1f; 1、看一下这个例子&#xff0c;可能更好…

大端小端详解

文章目录为什么有大端小端&#xff1f;大端&#xff1a;低位放在高地址&#xff0c;高位放在低地址小端&#xff1a;低位放在低地址&#xff0c;高位放在高地址面试考点&#xff1a;代码代码2一道面试题为什么有大端小端&#xff1f; 大端&#xff1a;低位放在高地址&#xff0…

详解volatile关键字

volatile字面意思&#xff1a;易变的。在计算机里&#xff0c;是防止优化的意思&#xff0c;然而是怎么防止优化的呢&#xff1f;待我一一道来哦。 先看这样一个例子&#xff1a; <span style"font-size:18px;">#include<iostream> using namespace std…

C语言 有符号字符型输出 面试题

1.第一题 int main() {int a 128;printf("%u\n", a);system("pause"); } 输出结果 128 #include <stdio.h> #include <stdlib.h>int main() {char a 128;printf("%u\n", a);system("pause"); } 输出结果 42949671…