关于函数模板和类模板的应用

一.泛类型编程的语法基础

1.template或template:T为类型,可以定义变量,类似于int ,float.
2.template关键字告诉编译器,现在要开始进行泛类型编程
3.举个小例子用swap实现交换
template
void Swap(T &a, T &b)
{
T c;
c = a;
a = b;
b = c;
}
void main()
{
int x1 = 1, y1 = 2;
Swap(x1, y1);//自动类型推导
printf("x1:%d,x2:%d\n", x1, y1);


float x2 = 2, y2 = 3;
Swap(x2, y2);//具体类型调用
printf("x2:%f,y2:%f", x2, y2);
system("pause");
}




从运行结果可以看出来,泛类型编程有两种调用方法:
(1)自动类型推导,编译器会根据你所定义的变量类型推导出调用的类型
(2)具体类型调用,自定义什么类型,编译器就执行哪种类型
****刚好这块用到了swap引用传递,我想起来昨天在牛客上刷题时遇到的一个小知识点,比较容易出错,在这里我作为小知识点加进去:
在这里我把值传递和引用传递做一个小比较:

1. 在函数定义格式上有不同:
值传递在定义处是:Exchg1(int x, int y);
引用传递在这义处是:Exchg1(int &x, int &y);

2. 调用时有相同的格式:
值传递:Exchg1(a,b);
引用传递:Exchg3(a,b);

3. 功能上是不同的:
值传递的函数里操作的不是a,b变量本身,只是将a,b值赋给了x,y函数里操作的只是x,y变量而不是a,b,显示a,b的值不会被Exchg1函数所修改。
引用传递Exchg3(a,b)函数里是用a,b分别代替了x,y。函数里操作的是a,b。



                                                                                                                                                                 


二.函数模板

1.函数模板可以像普通函数一样被重载
2.c++编译器优先考虑普通函数
3.如果函数模板可以产生一个更好的匹配,那么选择模板
4.可以通过空模板实参列表的语法限定编译器只通过模板匹配
5.函数模板不允许自动类型转换,而普通函数能够进行自动类型转换,在下面的代码中我会举例说明


                                                                                                 
函数模板的深入理解
——编译器并不是把函数模板处理成能够处理任意类型的函数
—— 编译器从函数模板通过具体类型产生不同的函数
——编译器会对函数模板进行两次编译
——在声明的地方对模板代码本身进行编译
——在调用的地方对参数替换后的代码进行编译
                                                                    

1.下面举代码例子说明(对数组和字符串进行排序打印)
template
void sortArray(T *a, int num)
{
int i = 0;
int j = 0;
T tmp;
for (i = 0; i < num; i++)
{
for (j = i + 1; j < num; j++)
{
if (a[i]>a[j])
{
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
}
}
}
template
void printfArray(T *a, int num)
{

int i = 0;
int j = 0;
for (i = 0; i < num; i++)
{
cout << a[i] <<" " ;
}
}
void main()
{
int a[10] = { 3, 2, 6, 5, 7, 8, 0 };
int num = sizeof(a) / sizeof(*a);
sortArray(a, num);
printfArray(a, num);
//此处就是泛型编程的第二种用法,具体类型调用
cout << endl;
char buf[] = "2378623jduhydujmasdn";
int len = strlen(buf);
sortArray(buf, len);
printfArray(buf, len);
system("pause");



注意:第一个运行结果前面之所以有四个零,是因为在初始化数组时,定义数组个数不够时,编译器默认后面的数字为0.
2.再举一个当函数模板遇上函数重载的例子
int Max(int a, int b)//普通函数
{
cout<<"int Max(int a, int b)"<return a > b ? a : b;
}


template//函数模板
T Max(T a, T b)
{
cout<<"T Max(T a, T b)"<return a > b ? a : b;
}


template
T Max(T a, T b, T c)//函数重载
{
cout<<"T Max(T a, T b, T c)"<return Max(Max(a, b), c);
}




void main()
{
int a = 1;
int b = 2;


cout<cout<(a, b)<

cout<

cout<


cout<system("pause");
return ;
}

注意:在执行cout<,然后再是两次T Max,是因为在定义函数时,返回的是 Max(Max(a,b),c);先进入该函数,然后进行啊,a,b比较函数,比较结果再与c进行比较

三.类模板

我会用两个小例子进行说明
1.
template
class AA
{
public:
AA(T a)
{
this->a = a;
}
void setA(T a)
{
this->a = a;
}
T getA()
{
return this->a;
}
protected:
private:
T a;
};


class BB : public AA
{
public:
//BB(int a, int b) : AA(a) 
BB(int a, int b) : AA(a) 
{
this->b = b;
}


private:
int b;
};


void main()
{
//要把类模板具体成类型后,才能定义变量
AA a(10);


BB b1(1, 2);
system("pause");
}

由于没有把BB定义成具体类型,因此会报错
2.

template
class Complex
{
public:
Complex(T r = 0, T i = 0){
Real = r;
Image = i;
}
Complex(T a){ Real = a; Image = 0; }
void print() const{
cout << '(' << Real << "," << Image << ')' << endl;
}
friend Complexoperator+(Complex&c1, Complex&c2)
{
T r = c1.Real + c2.Real;
T i = c1.Image + c2.Image;
return Complex(r, i);
}
private:
T Real, Image;
};
void main()
{
Complexc1(1, 2);
Complexc2(3, 4);
Complexc3= c1 + c2;
c3.print();
system("pause");


}


以上就是我总结关于模板的用法,希望能对你们有所帮助。

你可能感兴趣的