文章目录
1.泛型编程
当你熟悉了c++可重用代码的目标,这样做的很大的一个回报就是可以使用别人的代码,这正是类库的用武之地。今天学习了标准模板库(STL),他是一组用于处理各种容器对象的模板。STL演示了一中编程——泛型编程。
2.String类
2.1 构造字符串
先了解string的构造函数》毕竟对于类而言,最重要之一就是如何创建其对象。C++98用了7个构造函数,C11好像新增了两个。
下面是官方的7个构造函数:
default (1)
string();
copy (2)
string (const string& str);
substring (3)
string (const string& str, size_t pos, size_t len = npos);
from c-string (4)
string (const char* s);
from sequence (5)
string (const char* s, size_t n);
fill (6)
string (size_t n, char c);
range (7)
template <class InputIterator>
string (InputIterator first, InputIterator last);
2.2string类输入
对于C风格字符串,有三种方式:
char info[100];
cin>>info;
cin>>getline(info,1oo);//读一行
cin>>get(info,100);
对于string对象来说有两种:
string stuff;
cin>>stuff; //read up to:,discard:
getline(cin,stuff);
因为string对象的输入函数使用输入流,能够识别文件尾,他、因此也可以从文件中读取录入。
3.函数模板以及特化
3.1 什么是函数模板
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板就是将本来应该我们做的重复的事情交给了编译器
template <class T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
template <class T>
T add(T a, T b)
{
return a + b;
}
template <class T1,class T2>
T2 Add(const T1& a, const T2& b)
{
return a + b;
}
int Add(const int& a, const int& b)
{
return a + b;
}
在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供
调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然
后产生一份专门处理double类型的代码,对于字符类型也是如此。
3.2 函数模板的特化
函数模板
template <class T>
T Add(T& a, T& b)
{
return a + b;
}
函数模板的特化
template <>
char* Add<char*>(char*& a, char*& b)
{
strcat(a, b);
return a;
}
普通函数
char* Add(char*& a, char*& b)
{
strcat(a, b);
return a;
}
对于函数模板不能够处理的特殊类型,一般会定义一个此类型的普通函数,函数模板比较特殊特殊会比较少用。
template <class T, size_t N>
class Array
{
private:
T _array[N];
};
模板参数可分为:类型模板参数(class, typename), 非类型模板参数(数值类型)
非类型模板参数: 可以作为常量使用, 它的值需要在编译时确定
4.类模板及特化
4.1 类模板
template <class T1, class T2, class T3>
class Date
{
public:
Date(T1 year, T2 month, T3 day)
:_year(year)
, _month(month)
, _day(day)
{}
void Display();
/*{
cout << _year << "-" << _month << "-" << _day << endl;
}*/
private:
T1 _year;
T2 _month;
T3 _day;
};
如果在类外定义类模板的成员函数,需要加上泛型的声明,作用域为“类名<泛型参数>”
类模板不能进行隐式实例化,需要在类模板名字后跟 <>
4.2 类模板的特化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>
中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
特化之前需要存在基础类模板
template <class T1, class T2>
class A
{
public:
A()
{
cout << "A(T1, T2)" << endl;
}
private:
T1 _t1;
T2 _t2;
};
全特化--> 所有的参数都为具体类型
template <>
class A<int, char>
{
public:
A()
{
cout << "A(int, char)" << endl;
}
private:
int _t1;
char _t2;
};
偏特化: a. 部分特化
template <class T1>
class A<T1, double>
{
public:
A()
{
cout << "A(T1, double)" << endl;
}
private:
T1 _t1;
double _t2;
};
template <class T1>
class A<T1, char>
{
public:
A()
{
cout << "A(T1, char)" << endl;
}
private:
T1 _t1;
double _t2;
};
b. 对模板参数做进一步的限制
template <class T1, class T2>
class A<T1&, T2&>
{
public:
A()
{
cout << "A(T1&, T2&>" << endl;
}
};
5.模板分离编译
一个程序由若干个源文件共同实现,每个源文件单独编译生成目标文件,最后将所有的目标文件链接起来形成单一可执行文件的过程称之为分离编译模式。
a.h
template<class T>
bool IsEqual(const T& a, const T& b);
a.cpp
template<class T>
bool IsEqual(const T& a, const T& b)
{
return a==b;
}
main.cpp
#include"a.h"
int main()
{
IsEqual(1, 1);
IsEqual(1.0, 2.0);
return 0;
6 模板总结
1.模板参数
a.类型模板参数
b.非类型模板参数(一般为整数)(浮点数,字符串,自定义类型不能作为非类型模板参数)
2.模板特化:解决通用模板不能正确处理特殊类型的逻辑
a.函数模板特例化
前提:必须有一个是基础模板
template<>
返回值 函数名<具体类型…>(参数列表)
对于特殊化类型,一般定义一个普通函数即可
b.类模板特例化
前提:必须有一个基础模板
全特化:所有类型都进行特化
偏特化:
部分特化:只特化部分类型
限制特化:对通用的模板参数的类型进一步的限制
3.不支持分离编译
a.一般声明和定义都放在头文件中,".h",".hpp"
b.在定义模板的文件中进行实例化,不建议这种形式
模板特化应用:类型萃取。
【优点】
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
- 增强了代码的灵活性
【缺陷】 - 模板会导致代码膨胀问题,也会导致编译时间变长
- 出现模板编译错误时,错误信息非常凌乱,不易定位错误