039-C++之模板与泛型编程
本帖最后由 moc 于 2018-9-9 22:26 编辑模板:把函数或类要处理的数据参数化。
模板用于表达逻辑结构的相同,但具体数据元素类型不同的数据对象的通用行为。
1、函数模板
函数模板声明:
template <类型形式参数表>
类型 函数名(形式参数表)
{函数体}
函数模板定义由模板说明和函数定义组成;
函数说明的类属参数必须在函数的定义中至少出现一次;
函数参数表中也可以使用一般的参数。
// template关键字告诉C++编译器,现在开始泛型编程
// typename(也可为class) 告诉C++编译器 T为类型(T为类型, 可以参数化为int float等), 你不要乱报错
template<typename T>
void swap2(T &a, T &b)
{
T c;
c = a;
a = b;
b = c;
}
template<typename T, typename TT>
void print(T &a, TT &b)
{
cout << sizeof(T) << endl;
cout << sizeof(TT) << endl;
}
int main()
{
// 泛型编程的调用方式有两种
// 1.自动类型推导
int x = 1, y = 2;
swap2(x, y);
cout << x << y << endl;
// 2.具体类型调用
float x1 = 1.0, y1 = 2.0;
swap2<float>(x1, y1);
cout << x1 << y1 << endl;
int a;
char b = 'g';
print<int,char>(a, b);
system("pause");
return 0;
}
2、函数模板遇上函数重载
当同时存在重载函数和函数模板时,遵守下面的约定:
1. 函数模板可以像普通函数一样被重载
2. C++编译器优先考虑普通函数
3. 如果函数模板可以产生一个更好的匹配,那么选择模板
4. 可以通过空模板实参列表的语法限定编译器只通过模板匹配
int Max(int a, int b)
{
cout << "int Max(int a, int b)" << endl;
return a > b ? a : b;
}
template<typename T>
T Max(T a, T b)
{
cout << "T Max(T a, T b)" << endl;
return a > b ? a : b;
}
template<typename T>
T Max(T a, T b, T c)
{
cout << "T Max(T a, T b, T c)" << endl;
return Max(Max(a, b), c);
}
void main()
{
int a = 1;
int b = 2;
cout << Max(a, b) << endl; // 优先选择普通函数
cout << Max<>(a, b) << endl; // 空模板实参列表强制要求使用模板函数
cout << Max(3.0, 4.0) << endl;
cout << Max(5.0, 6.0, 7.0) << endl;
cout << Max('a', 100) << endl; // 函数模板不允许自动类型转化 ,普通函数可以进行自动类型转化
system("pause");
return;
}
注意:函数模板不允许自动类型转换,普通函数可以。
3、函数模板的原理探究
C文件的处理过程了解:
①预编译(预处理)
处理所有注释,以空格代替;
将所有的#define删除,并展开所有的宏定义;
处理条件编译指令#if, #ifdef, #elif, #else, #endif;
处理#include,展开被包含文件
保留编译器需要使用的#pragma指令;
预处理指令:gcc -E file.c- ohello.i
②编译
对预处理的文件进行一系列词法分析,语法分析和语义分析;
词法分析主要分析关键字、标识符、立即数等是否合法;
语法分析主要分析表达式是否遵循语法规则;
语义分析是在语法分析的基础上进一步分析表达式是否合法;
分析结束后进行代码优化生成相应的的汇编代码文件
编译指令: gcc -S file.c- ohello.s
③汇编
汇编器将汇编代码转变为机器可以执行的指令
每个汇编语句几乎都对应一条机器指令
汇编指令: gcc -c file.s- o hello.o
函数模板原理:
① 编译器并不是把函数模板处理成能够处理任意函数类型的函数;
② 编译器从函数模板通过具体类型产生不同的函数;
③ 编译器会对函数模板进行两次编译;
在声明的地方对模板代码本身进行编译,
在调用的地方对参数替换后的代码进行编译。
4、类模板
类模板用于实现类所需数据的类型参数化;类模板在表示数组、表、图等数据结构显得特别重要,这些数据结构的表示和算法不受所包含元素的类型影响。
template <类型形式参数表>
类声明
类模板的用法和函数模板类似。
// template关键字告诉C++编译器,现在开始泛型编程
// typename 告诉C++编译器 T为类你不要乱报错
template<typename T>
class AA
{
public:
AA(T x) { t = x; }
void setA(T a)
{
this->a = a;
}
T getA()
{
return this->a;
}
protected:
private:
T a;
};
class BB : public AA<int>
{
public:
BB(int a, double x) :AA<int>(a) { b = x; }
protected:
private:
double b;
};
int main06()
{
// 要把类模板具体成类型 才能实例化
AA<int> a(5);
system("pause");
return 0;
}
类模板与static成员:
① 从类模板实例化的每个模板类都有自己的类模板数据成员,该类模板的所有对象共享一个static类;
② 和非类模板的static数据成员一样,模板类的static数据成员也应该在文件范围内定义和初始化;
类模板遇上友元函数:
由于类模板的两次编译会导致写在类外面的友元函数的实现编译不能通过。
解决办法:把在类中声明友元函数直接写成friend 函数名(参数){函数体};也就是把函数体加进来,这样也不用再在外面声明。
页:
[1]