2018年6月15日星期五 小雨
模板
/*重载函数
include
using namespace std;
void swap(int &rx,int &ry)
{
int temp=rx;
rx=ry;
ry=temp;
}
void swap(float&ra,float &rb)
{
float temp=ra;
ra=rb;
rb=temp;
}
void swap(double&a,double &b)
{
double temp=a;
a=b;
b=temp;
}
int main()
{
int x=2,y=5;
cout<<"交换前,x:"<
using namespace std;
template//定义了一个模板类型Type,template是声明模板的关键字。尖括号中的模板类型跟在关键字template之后,也可以叫做参数。
void Tswap(Type &rx,Type &ry)//由于swap函数与标准库中的swap重名,因此将swap函数换成了Tswap。
{
Type temp=rx;
rx=ry;
ry=temp;
}
int main()
{
int x=2,y=5;
cout<<"交换前,x:"<
可以定义多个模板类型,如:template//每个参数之间必须用逗号隔开,并且每个参数都必须重复使用关键字class,关键字class表示该参数是一个类型,它与表示类的class无关。其中的类型名可以任意取,不过由于字幕T能使人联想到单词Type,因此一般都会选择T作为类型名。
2018.6.21-6.22
具体化函数模板解决重载问题
c++模板提供了一个具体化函数定义的特征,又称显示具体化。我们可以为Swap()函数的两个不具体参数T &a和T &b定义两个具体的参数。people &a,people &b;
include
using namespace std;
template
void Swap(T &a,T &b);
struct people
{
char name[10];
int age;
};
template<>void Swap(people&p1,people&p2);
//void Swap(people&a,people&b);
void show(people&p);
int main()
{
int i=10,j=20;
cout<<"初始值i="<
void Swap(T &a,T &b)
{
T temp;
temp=a;
a=b;
b=temp;
}
template<>void Swap(people &a,people &b)
//void Swap(people&a,people&b)
{
int Age;
Age=a.age;
a.age=b.age;
b.age=Age;
}
void show(people&p)
{
cout<
具体化函数模板与实例化模板函数
具体化函数模板与实例化模板函数
由类模板实例化得到的类叫模板类。假设抢劫这个构思是一个函数模板,而抢劫的行为是模板函数(模板生成的函数),它是能够实施的动作,而不是构思。把已确立好目标的抢劫方案叫做具体化函数模板,把已确立好目标的抢劫行为叫做显示实例化模板函数。template<>void Swap (people &p1,people &p2);//声明了一个具体化函数模板,template void Swap (people &a,people &b);//显示地声明了一个实例化模板函数
include
using namespace std;
template
void show(T a){cout<(char&);//显示声明了一个实例化模板函数,它的参数为char型字符的引用,这样在程序编译时会根据上面定义的函数模板强制创建void show(char &a){cout<
普通函数、函数模板 与具体化函数模板的优先级
普通函数、函数模板 与具体化函数模板的优先级
函数模板的匹配
函数模板的匹配
include
using namespace std;
struct people
{
char name[50];
int age;
};
template
void show(T t[],int n)
{
cout<<"执行函数模板void show(T t[],int n)\n";
for(int i=0;i
void show(T * t[],int n)
{
cout<<"执行函数模板void show(T * t[],int n)\n";
for (int i=0;i
类模板的定义
类模板的定义
include
using namespace std;
template //定义了一个类型为T的模板
class people //定义了一个people类
{
public:
people(T x,T y):X(x),Y(y){}
T getX(){return X;}
T getY(){return Y;}
private:
T X,Y; //用T类型声明了2个变量X和Y,这2个变量分别应用到第7行的构造函数、第8行的getX()和第9行的getY()函数中。
};
int main()
{
people Jack(3,4);//调用people类的构造函数初始化该类的jack对象,people是一个类,其后的则告诉编译器这不是一个普通类,而是一个类模板,编译器将根据这个类模板生成一个类,并具体化模板参数T为int。
cout<
复杂类模板
复杂类模板
把一个类作为数据类型传递给模板,由于类与普通数据不同,因此我们需要重载类模板的复制构造函数和重载运算符函数。
include
using namespace std;
const int size=10;
class people
{
public:
people(int i):x(i){}
people():x(0){}
int GetAge()const{return x;}
void show()const{cout<
class num
{
public:
num(int Tsize=size);
num(const num&r);
~num(){delete[]pt;}
num&operator=(const num&);
T&operator[](int offset){return pt[offset];}
const T&operator[](int offset)const
{
return pt[offset];
}
int GetSize() const {return numsize;}
private:
int numsize;
T*pt;
};
template
num::num(int size):numsize(size)
{
pt=new T[size]; //该语句在堆中创建了一个类型为T的数组,并右指针pt指向该数组,由于T被具体为people,size值为10,该语句相当于pt =new people[10]
for (int i=0;i
num::num(const num&r)
{
numsize=r.GetSize();
pt=new T[numsize];
for (int i=0;i
num&num::operator=(const num&r)
{
if (this==&r)
{
return *this;
delete[]pt;
numsize=r.GetSize();
pt=new T[numsize];
for (int i=0;ione;
numtwo;
people*p;
for (int i=0;i
类模板的成员函数的定义方法,假如是在类模板中写内嵌函数,假如是在类模板中写内嵌函数,那么可以直接写:T& operator[](int offset){return pt[offset];}假如是在类模板的外部写成员函数,那么必须注明它所属的类,其中,T为返回类型,num为模板名称,它后面加作用域解析符::,表示后面的operator函数属于该类模板T& num::opertator[](int offset){return pt[offset];}
数组模板
数组模板
我们可以定义一个数组模板,并用该模板声明类模板中的数组成员,如:templateclass people{public:people();people(const T&t);T &operator[](int i);void show();private:T a[n];//声明了一个数组a[n]}
include
using namespace std;
template
class people
{
public:
people();
people(const T&t);
T&operator[](int i);
void show();
private:
T a[n];
};
template
people::people()
{
cout<<"执行构造函数\n";
for (int i=0;i
people::people(const T&t)
{
cout<<"执行带一个参数的构造函数\n";
for (int i=0;i
T&people::operator[](int i)
{
cout<<"执行下标运算符函数operator[]\n";
if (i<0||i>=n)
{
cerr<<"超出数组限制,第:"<
void people::show()
{
for (int i=0;ione;
one.show();
people*p=new people[4];//在堆中创建了4个对象,这4个对象按顺序排列在一个数组中,我们把这个数组叫对象数组。
for (int i=0;i<9;i++)
{
p[i]=one[i];//one[i]将会调用第33行的operator[]函数,第7行的输出结果证实了这一点。
p[i].show();
}
return 0;
}
people*p=new people[4];//在堆中创建了4个对象,这4个对象按顺序排列在一个数组中,我们把这个数组叫对象数组。由于people类是一个类模板,因此必须写成people,而不是people,其他都相同。
对象数组模板
对象数组模板
我们可以直接使用对象数组模板来构造对象数组,如:
people ,10>two;//创建了一个包含10个对象元素的对象数组two,每个对象又拥有一个5个int型元素的数组,因此它可以看作如下二维数组:
int two[10][5];
include
using namespace std;
template
class people
{
public:
people();
people(const T&t);
T&operator[](int i);
void show();
private:
T a[n];
};
template
people::people()
{
cout<<"执行构造函数\n";
for (int i=0;i
people::people(const T&t)
{
cout<<"执行带一个参数的构造函数\n";
for (int i=0;i
T&people::operator[](int i)
{
cout<<"执行下标运算符函数operator[]\n";
if (i<0||i>=n)
{
cerr<<"超出数组限制,第"<
void people::show()
{
for (int i=0;i,3>two;//因为对象two的3个成员也是对象,对象two加上它的3个对象成员一共是 4个对象。
int obj=1;
for (int i=0;i<4;i++)
{
int sum=1;
for (int j=0;j<2;j++)
{
cout<<"\ntwo["<
具有多个参数的模板
具有多个参数的模板
一个模板中可以有多个参数,如:
template
include
include
using namespace std;
template
class People
{
public:
T1&getx();
T2&gety();
T1 getx()const{return x;}
T2 gety()const{return y;}
People(const T1&a,const T2&b):x(a),y(b){cout<<"构造函数\n";}//第12行
private:
T1 x;
T2 y;
};
template
T1&People::getx()
{
return x;
}
template
T2&People::gety()
{
return y;
}
int main()
{
Peopleone[4]={
People("hello world",5),
People("good morning",6),
People("sit down please",8),
People("have a cup of tea",2)
}; //这会调用第12行的构造函数,T1类型的参数a用来接收字符串,T2类型的参数b用来接收数值。
int num=sizeof(one)/sizeof(People);//初始化完成后,此行用来计算对象的数目,即对象数组one共有几个对象。
cout<<"输出对象数组one的所有元素:\n";
for (int i=0;i
构造函数
构造函数
构造函数
构造函数
输出对象数组one的所有元素:
5: hello world
6: good morning
8: sit down please
2: have a cup of tea
修改one[3]的数据并输出:
6: get out of here
请按任意键继续. . .
为模板参数提供默认值
为模板参数提供默认值
template
peopleone;
peopleone;//与上一句相同
约束模板
约束模板
T Max(T a,T b)
{
return(a>b)?(a):(b);
}
>运算符对数字和为类重载了operator>可以比较,但若必经的类型是两个指向字符串的指针,则比较的是两个地址,而不是数值。因此必须使用strcmp()函数对两个指针指向的字符串进行比较,而不能使用运算符">"。当然前提是T的类型必须是char *,因此我们需要具体化该函数模板的参数和功能,如:char*Max(char*a,char*b){if(strcmp(a,b)>0)return a;elsereturn b;}该函数的两个参数是char*,它的功能是用strcmpy函数比较指针所指向的字符串,而不是指针。这个特定的用来替换函数模板的函数,我们把他叫做特定模板函数,或者是具体化模板实例。
//接下来的程序演示了具体化模板函数的使用情况,如下:
include
include
using namespace std;
template
T Max(T a,T b) 你
{
return(a>b)?(a):(b);
}
char*Max(char*a,char*b) //具体化了函数目标的参数和功能,它是一个专门用来比较字符串的特定函数,或者说用来替换函数模板的普通函数。
{
if(strcmp(a,b)>0)
return a;
else
return b;
}
int main()
{
int x=2,y=3;
cout<
6.23
嵌套类模板
嵌套类模板
include
using namespace std;
template
class One
{
public:
One(T1 t,int i):first(t),second(i){}
template
T1 get(T1 t1,T2 t2)
{
cout<<"first.get()返回"<
class two
{
public:
two(T3 t3=0):x(t3){}
void show()const{cout<first;
twosecond;
};
int main()
{
Oneone(3.5,4);
one.show();
cout<<"\n执行get函数\n";
cout<
将模板用作参数
将模板用作参数
a tempplate
b templateclass T1>
template
class human //2-8行使用a模板声明了一个类模板human
{
public:
T Getage(){cout<class T1>
class people
{
public:
int Getage(){return t1.Getage();
private:
T1t1;//int具体化了所包含的模板的参数类型,即将第9行所包含的模板中的参数类型T具体化为int。
}
include
include
using namespace std;
template
class human
{
public:
human(){}
T GetAge(){return age;}
T GetStr(){return name;}
void SetAge(T &a){age=a;}
void SetStr(T &s){name=s;}
private:
T name;
T age;
};
templateclass T1>
class people
{
public:
people(){}
int GetAge(){return s1.GetAge();}
void SetAge(int &a){s1.SetAge(a);}
string GetStr(){return s2.GetStr();}
void SetStr(string &s){s2.SetStr(s);}
private:
T1s1;
T1s2;
};
int main()
{
peopleJack;
int i=8;
string str="hello";
Jack.SetAge(i);
cout<模板和友元
类模板也有朋友,类模板的朋友共有3种情况
- 非模板友元类或函数(不是模板)。
- 通用模板友元类或函数(通用的模板)。
- 特定类型的模板友元类或函数(特定的模板)。
非模板友元类或函数
非模板友元类或函数指的是普通友元类或友元函数。
静态成员和模板
类的静态成员是属于类的成员,而不是属于某个对象的成员,因此这个静态成员应该在全局进行初始化,而不是在类中,这样,类中的每个对象都共同享有一个静态成员。类模板也可以声明静态成员,与普通类相同,类模板的对象也共同拥有这样的静态成员,并且这个静态成员也必须在全局进行初始化。
include
using namespace std;
template
class num
{
public:
num():x(0){}
T get(){return y;}
private:
T x;
static T y;
};
template
T num::y=1;
int main()
{
numone;
cout<
标准模板库
容器
容器是包含其他对象的对象。主要分为
顺序容器:提供对自身元素的顺序或者随机访问。
关联容器:关联容器则过滤掉一些元素,只按关键值访问有关元素。
顺序容器
标准C++提供了3种顺序容器,分别为vector、list和deque.
1.向量容器
vector是一个经过优化并且用来提供对其元素进行快速访问的容器。这个容器在标准命名空间std的头文件中定义,因此我们在使用它时要加上头文件include.vector可以根据我们的需要增长。/*第1个参数是class T,是向量中各个元素的类型;第2个参数是一个分配函数类,分配函数就是负责为容器中的元素分配和释放内存的内存管理器。假如我们省略第2个参数,那么容器模板将默认使用allocator类,即分配函数类,这个类以标准方式分配和释放内存,即用运算符new()创建内存,用运算符delete释放内存*/template>class vector{//类的成员};
a//向量的程序代码如下:
include
include
include
using namespace std;
const int num=2;
int main()
{
vectorprice(num);//传递一个double类型给vector类模板,这个类型会替换该类的第1个参数T.小括号中的num表示元素的个数。容器price包含两个double变量。
vectorbook(num);
cout<<"开始录入"<>price[i];
cin.ignore();
}
for (int i=0;i
以上演示了容器与数组相同的地方,接下来将介绍容器与数组的不同。假如我们定义了一个背包,这个背包的容量设置为50L,假设我们有1L的塑料桶50个,我们将它统统塞到背包中,如:vector backpack(50);//pail是塑料桶类,backpack是背包这个容器,50表示这个背包的容量为50L,这样,编译器将为50这个塑料桶分配足够的内存空间,backpack这个容器每个pail元素都是调用pail类的默认构造函数来创建的。backpace.size();//查看这个向量中有多少个元素。backpace.capacity();//返回的是当前容器在重新进行内存分配以前所能容纳的元素数量。backpace.empty();//检测这个向量中是否存在元素。backpace[2]=9;//给向量中的某一元素赋值backpace.push_back(9);//这个成员函数将9塞进backpace这个向量中,这个9将排到向量backpace的最后。当然,9也可以是变量或者对象,如:int x=9;backpace.push_back(x);或者string str="hello world";backpace.push_back(str);/*由于我们是以复制变量或者对象的方式将其添加到向量中,因此,string类必须定义一个复制构造函数,否则push_back()函数无法复制str对象,也就无法将其添加到向量backpace中。由于string类的设计者已经为其定义好了复制否则偶函数,因此我们可以成功地将str对象添加到向量backpace中,但是假如str是自定义类中的一个对象,如:people str;//我们就必须为这个people类定义复制构造函数,以便于push_back()函数进行复制工作。*/
//接下来我们看一个程序,这个程序将演示上面的所有知识点,如下:
include
include
include
using namespace std;
/*为了说明容器类的push_pack()成员函数会调用对象的复制构造函数复制对象,然后将复制后的对象添加到容器中,声明了people类。该类同时拥有一个默认构造函数,一个赋值运算符operator=()函数和4个用来设置和读取私有数据成员的函数*/
class people
{
public:
people();
people(const string&name,const int age);
people(const people&r);
~people();
void SetName(const string&name);
string GetName()const;
void SetAge(const int age);
int GetAge()const;
people&operator=(const people&r);
private:
string theName;//string类创建了一个theName对象,这个theName对象被作为people类的私有成员,或者说people类包含一个string类对象。
int theAge;
};
people::people():theName("默认创建的新人"),theAge(52){}
people::people(const string&name, const int age):theName(name),
theAge(age){}
people::people(const people&r):theName(r.GetName()),theAge(r.GetAge())//定义了people类的复制构造函数。
{
cout<<"复制构造函数执行...\n";
}
people::~people(){cout<<"析构函数执行\n";}
void people::SetName(const string&r)
{
theName=r;
}
string people::GetName()const
{
return theName;
}
void people::SetAge( const int age)
{
theAge=age;
}
int people::GetAge()const
{
return theAge;
}
people&people::operator =(const people&r)
{
cout<<"operator=函数执行...\n";
theName=r.GetName();
theAge=r.GetAge();
return*this;
}
ostream &operator<<(ostream&out,const people&r)//作用是输出该类的两个私有成员。
{
out< //为了演示向量中各个成员函数的用法,声明了一个函数模板show。
void show(const vector&v);
typedef vectorman;//使用typedef简化vector的输入操作,这样当我们输入man时,其实就是输入vector的man创建了一个空向量non,这是调用vector类的默认构造函数来实现的,由于该函数没有为向量分配内存空间和元素,因此第67行调用show函数并将non作为参数传递进去后,我们看到向量的大小和容量都是0,并且empty函数的判断结果为空,即元素为空。
cout<<"non:\n";
show(non);//67行
man manyMan(3);//vector manMan(3) ,定义了一个包含3个元素的向量manMan,由于元素类型为people,因此实际上manMan包含的是3个people类对象。因为添加到向量和总的对象是复制后的对象,因此这里连续调用了3次people类的复制构造函数。
cout<<"manyMan(3):\n";
show(manyMan);//调用show函数并将向量manMan作为参数传递进去,size()=3 capacity()=3 不为空
-/*71到73为每个元素赋值,这3个值说我们在62-64行定义的3个people类对象*/
manyMan[0]=Mary;//71
manyMan[1]=Tom;//73
manyMan[2]=Jesson;//73
cout<<"为容器manyMan(3)分配3个人后:\n";
show(manyMan);
people Ketty("Ketty",58);manyMan.push_back(Ketty);
manyMan.push_back(Jack);
cout<<"manyMan()增加2个人后:\n";
show(manyMan);
manyMan[0].SetName("Rose");
manyMan[0].SetAge(16);
cout<<"设置manyMan[0]后:\n";
system("pause");
return 0;
}
template
void show(const vector&v)
{
cout<<"max_size()="<
声明:本文部分素材转载自互联网,如有侵权立即删除 。
© 版权声明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!邮箱:cxysz1@tom.com
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
THE END
暂无评论内容