C++面向对象入门(三十六)模板概念和初步认识函数模板

强类型语言的特点:
1 程序可靠性较高:在编译运行前必须经过严格的类型检查, 达到在运行前就检查出类型不兼容的错误.
2 灵活性较低: 对于默写处理逻辑完全一样, 但是数据类型不同的变量的操作必须按照类型分别定义.
解决强类型的严格性和灵活性的冲突的途径:
1 使用宏函数: 方便, 但是可能不带来其他安全问题, C++不提倡
2 为每个数据类型重载相同的函数, 麻烦
3 放松类型检查, 在编译时忽略, 推迟到运行期间作类型匹配检查, 可能在程序运行期间出现类型不兼容的情况
4 将数据类型作为参数(类属机制Genericity)
C++通过模板机制实现类属机制
模板机制: 一种参数化多态性的工具, 为逻辑功能相同而类型不同的程序提供代码共享机制
C++中的模板机制, 模板并非实实在在的函数或类, 仅仅是函数或类的描述, 模板运算对象的类型不是实际的数据类型,
而是一种参数化的类型(类属类型), 根据使用类似类型的构件, 又分为:
1 类模板:对一批仅有数据类型不同类的抽象, 只需为这一批类组成的整个类家族创建一个类模板, 然后给出一套程序代码, 就
可以用来生成多种具体类, 即模板类. 由于类模板需要一种或多种类型参数, 因此又被称为参数化类
优点:提高编程效率, 提高代码可重用性
类和类模板: 类是对一族具有公共性质的对象的抽象, 而类模板则是对一组具有公共性质的类的抽象, 类模板是更高层次的抽象化
如何定义类模板?
template<模板参数表>
class <类模板名>
{
 <类成员声明>
}
使用类模板的注意事项:
1 模板参数表包含一个多个用逗号分开的类型, 参数项可以包含基本数据类型, 也可以包含类类型, 如果是类类型, 必须加前缀class
或typename
2 类模板的成员函数和重载运算符必须为模板函数, 可以在类内定义, 定义方式和定义成员函数一致, 也可以放在类模板外部, 此时
定义方式如下
template<模板参数名>
<返回值类型> <类模板名>< <类型名表> >::<成员函数名>(<参数表>)
{
 <函数体>
}
3 与函数模板不同的是, 函数模板的实例化是由编译系统在处理函数调用时自动完成, 而类模板的实例化必须在程序中显式地指定
在类模板实例化为模板类时(使用类模板经实例化而成的具体类), 类模板中的成员函数自动实例化为模板函数
如何定义模板类对象
<类模板名>< <类型实参表> > <对象名>(<实参表>)
对于上述定义方式字段的解释:
类名名表: 类模板定义中的模板参数表中的参数名
如何实例化类模板?
语法:
<类模板名> < <类型实参表> >
2 函数模板: 可以一次定义出具有共性(除类型参数外, 其余全部相同)的一组函数, 同时也可以处理多种不同类型数据的函数
优点:增强了函数设计的通用性
如何定义函数模板: 先实现函数模板, 然后实例化构造出相应的模板函数进行调用执行
定义函数模板的语法:
template<模板参数表>
<返回值类型> <函数名>(<参数表>)
{
 <函数体>
}
模板参数表的定义语法;
typename(class) 模板参数名,...
使用函数模板的注意事项:
1 模板参数可以在函数的任何地方使用
2 函数的参数表可以使用模板参数, 也可以使用一般类型参数(基本类型, 用户自定义类型), 但参数表至少又一个形参的
类型必须使用模板参数表的模板参数,
3 模板参数表中的每一个模板参数都必须在参数表中得到使用
4 函数模板的声明和定义必须是全局作用域, 模板不能被声明为类的成员函数
5 编译器不会为没有用到的任何类型生成相应的模板函数
6 一个类型无论使用多少次函数模板, 都只为该类型生成一个模板函数      
 
函数模板的代码示例:
#include <iostream>
using namespace std;

/*
强类型语言的特点:
1 程序可靠性较高:在编译运行前必须经过严格的类型检查, 达到在运行前就检查出类型不兼容的错误.
2 灵活性较低: 对于默写处理逻辑完全一样, 但是数据类型不同的变量的操作必须按照类型分别定义.
解决强类型的严格性和灵活性的冲突的途径:
1 使用宏函数: 方便, 但是可能不带来其他安全问题, C++不提倡
2 为每个数据类型重载相同的函数, 麻烦
3 放松类型检查, 在编译时忽略, 推迟到运行期间作类型匹配检查, 可能在程序运行期间出现类型不兼容的情况
4 将数据类型作为参数(类属机制Genericity)
C++通过模板机制实现类属机制
模板机制: 一种参数化多态性的工具, 为逻辑功能相同而类型不同的程序提供代码共享机制
C++中的模板机制, 模板并非实实在在的函数或类, 仅仅是函数或类的描述, 模板运算对象的类型不是实际的数据类型, 
而是一种参数化的类型(类属类型), 根据使用类似类型的构件, 又分为:
1 类模板:对一批仅有数据类型不同类的抽象, 只需为这一批类组成的整个类家族创建一个类模板, 然后给出一套程序代码, 就
可以用来生成多种具体类, 即模板类. 由于类模板需要一种或多种类型参数, 因此又被称为参数化类
优点:提高编程效率, 提高代码可重用性
类和类模板: 类是对一族具有公共性质的对象的抽象, 而类模板则是对一组具有公共性质的类的抽象, 类模板是更高层次的抽象化
如何定义类模板?
template<模板参数表>
class <类模板名>
{
 <类成员声明>
}
使用类模板的注意事项:
1 模板参数表包含一个多个用逗号分开的类型, 参数项可以包含基本数据类型, 也可以包含类类型, 如果是类类型, 必须加前缀class
或typename
2 类模板的成员函数和重载运算符必须为模板函数, 可以在类内定义, 定义方式和定义成员函数一致, 也可以放在类模板外部, 此时
定义方式如下
template<模板参数名>
<返回值类型> <类模板名>< <类型名表> >::<成员函数名>(<参数表>)
{
 <函数体>
}
3 与函数模板不同的是, 函数模板的实例化是由编译系统在处理函数调用时自动完成, 而类模板的实例化必须在程序中显式地指定
在类模板实例化为模板类时(使用类模板经实例化而成的具体类), 类模板中的成员函数自动实例化为模板函数
如何定义模板类对象
<类模板名>< <类型实参表> > <对象名>(<实参表>)
对于上述定义方式字段的解释:
类名名表: 类模板定义中的模板参数表中的参数名
如何实例化类模板?
语法:
<类模板名> < <类型实参表> >
2 函数模板: 可以一次定义出具有共性(除类型参数外, 其余全部相同)的一组函数, 同时也可以处理多种不同类型数据的函数
优点:增强了函数设计的通用性
如何定义函数模板: 先实现函数模板, 然后实例化构造出相应的模板函数进行调用执行
定义函数模板的语法:
template<模板参数表>
<返回值类型> <函数名>(<参数表>)
{
 <函数体>
}
模板参数表的定义语法;
typename(class) 模板参数名,...
使用函数模板的注意事项:
1 模板参数可以在函数的任何地方使用
2 函数的参数表可以使用模板参数, 也可以使用一般类型参数(基本类型, 用户自定义类型), 但参数表至少又一个形参的
类型必须使用模板参数表的模板参数,
3 模板参数表中的每一个模板参数都必须在参数表中得到使用
4 函数模板的声明和定义必须是全局作用域, 模板不能被声明为类的成员函数
5 编译器不会为没有用到的任何类型生成相应的模板函数
6 一个类型无论使用多少次函数模板, 都只为该类型生成一个模板函数          
*/
//定义函数模板
template<typename T>
T min(T a, T b)
{
 return a < b ? a : b;
}
//尝试在函数模板参数表中不使用模板参数, 仅在返回值类型和函数内使用
template<typename E>
E func1(int i, double d)
{
 cout << i << " " << d << endl;
 E e;
 return e;
}
//没有报错
//但在使用函数模板时会报错
//尝试在函数模板参数表中只使用部分模板参数
template<typename E, typename V>
E func2(E e)
{
 cout << e << endl;
}
//没有报错
//但在使用函数模板时会报错
class A53
{
private:
 int x;
 int y;
public:
 A53();
 A53(int, int);
 bool operator<(const A53 &a);
 friend ostream &operator<<(ostream &cout, const A53& a);
};
int main()
{
 double d1, d2;
 d1 = 3.7;
 d2 = 5.3;
 cout << d1 << " and " << d2 << " min is " << min(d1, d2) << endl;
 int i1, i2;
 i1 = 12;
 i2 = 34;
 cout << i1 << " and " << i2 << " min is " << min(i1, i2) << endl;
 char c1, c2;
 c1 = 'a';
 c2 = 'A';
 cout << c1 << " and " << c2 << " min is " << min(c1, c2) << endl;
 A53 a1(2, 1);
 A53 a2(1, 3);
 A53 a3(2, 2);
 cout << a1 << " and " << a2 << " min is " << min(a1, a2) << "}" << endl;
 cout << a1 << " and " << a3 << " min is " << min(a1, a3) << "}" << endl;
 cout << a2 << " and " << a3 << " min is " << min(a2, a3) << "}" << endl;
 A53 a4;
 //A53 a = func2(a4);
 //没有与参数类型匹配的函数模板'func2'实例
 // 参数类型为(A53)
 //func1(1, 2.5);
 //没有与参数类型匹配的函数模板'func2'实例
 // 参数类型为(int, double)
 system("pause");
}
A53::A53()
{
 cout << "A53" << endl;
}
A53::A53(int x, int y):x(x),y(y) {}
bool A53::operator<(const A53 & a)
{
 if (x == a.x)
 {
  return y < a.y;
 }
 return x < a.x;
}
ostream & operator<<(ostream & cout, const A53 & a)
{
 cout << "A53{x:" << a.x << ", y:" << a.y;
 return cout;
}

 

posted @ 2020-09-02 15:16  DNoSay  阅读(277)  评论(0编辑  收藏  举报