您的位置:首页 > 编程语言 > C语言/C++

C++基础之模板

2016-07-16 17:48 295 查看
     之前在看android binder代码时,看到大量使用了模板机制,虽然之前知道模板这个概念,也会使用,但没留下痕迹。任何技巧只有自己亲手实践过,才会记忆深刻。于是即将有此博文。呵呵,我们开始吧。博客中如有错误的地方,欢迎大家指正,我们共同学习,共同进步。

        模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型.使用模板的目的就是让程序员编写与类型无关的代码。比如下面的例子:

                                                                     int max(int x,inty){return (x>y)?x:y;}

                                                                     float max(float x,float y){return (x>y)?x:y;}

                                                                     double max(double x,double y){return (x>y)?x:y;}

        函数模板可以用来创建一个通用的函数,以支持多种不同的形参,避免重载函数的函数体重复设计。它的最大特点是把函数使用的数据类型作为参数,已使函数可以传递不同类型的参数,而不用修改代码。

1.函数模板声明形式

template<class param1,class param2,......> 返回值 函数名(参数列表)

{

           函数体

}

函数模板还是很简单的,其中class关键字可以用typename代替,而且之后的形参可以有多个。<>括号中的参数叫模板形参。在编译阶段就能确定具体的形参类型。我们不用关心类型。具体可以看看例子就知道了。

#include<iostream>
using namespace std;

template<typename T>
T max1(T x,T y){
return (x>y)?x:y;
}

int main(){
int a =6;
int b =9;
cout<<"max:"<<max1(a,b)<<endl;
return 0;
}
打印结果:max:9

在看android framework的代码时,函数模板用的还不是很多的。下面的函数几个需要注意的地方引用刃熊 weaponX的博文

①  如果在全局域中声明了与模板参数同名的对象函数或类型则该全局名将被隐藏在下面的例子中tmp 的类型不是double 是模板参数Type

typedef double Type;

template

Type min( Type a, Type b )

{

// tmp 类型为模板参数 Type

// 不是全局 typedef

Type tmp = a < b ? a : b;

return tmp;

}

 

②  在函数模板定义中声明的对象或类型不能与模板参数同名

template

Type min( Type a, Type b )

{

// 错误: 重新声明模板参数 Type

typedef double Type;

Type tmp = a < b ? a : b;

return tmp;

}

 

③  模板类型参数名可以被用来指定函数模板的返回位

// ok: T1 表示 min() 的返回类型

// T2 和 T3 表示参数类型

template

T1 min( T2, T3 );

 

④  模板参数名在同一模板参数表中只能被使用一次,但是模板参数名可以在多个函数模板声明或定义之间被重复使用

// 错误: 模板参数名 Type 的非法重复使用

template

Type min( Type, Type );

// ok: 名字 Type 在不同模板之间重复使用

template

Type min( Type, Type );

template

Type max( Type, Type );

 

⑤  如果一个函数模板有一个以上的模板类型参数则每个模板类型参数前面都必须有关键字class 或typename

// ok: 关键字 typename 和 class 可以混用

template

T minus( T*, U );

// 错误: 必须是 或

template

T sum( T*, U );

 

⑥ 为了分析模板定义编译器必须能够区分出是类型以及不是类型的表达式对于编译器来说它并不总是能够区分出模板定义中的哪些表达式是类型例如如果编译器在模板定义中遇到表达式Parm::name 且Parm 这个模板类型参数代表了一个类那么name 引用的是Parm 的一个类型成员吗.

template

Parm minus( Parm* array, U value )

{

Parm::name * p; // 这是一个指针声明还是乘法乘法

}

2.类模板声明形式

template <class T1,class T2,......> class  name{

        类中数据与方法

};

类模板的格式和函数模板有很多相识的地方,同样关键字可以是class和typelame,模板形参可以是多个。剩下的在类中的数据与方法,如果用到的是模板形参就要把类型改成模板形参列表中的类型。还是举一个小例子吧.

实例代码:

#include<iostream>
using namespace std;

template<class T>
class test{
    public:
        T hello(T a,T b);
        T hello1(T a,T b);
};

template<class T>
T test<T>::hello(T a,T b){
    cout<<"hello world1"<<endl;
    return a+b;
}
template<class T>
T test<T>::hello1(T a,T b){
    cout<<"hello world2"<<endl;
    return a+b;
}

int main(){
    test<int> *t = new test<int>();
    cout<<"a+b="<<t->hello(6,8)<<endl;
    cout<<"a+b="<<t->hello1(6,8)<<endl;
    return 0;
}


打印结果:

hello world1

a+b=14

hello world2

a+b=14

需要注意的地方:

1).如果类的方法是写在外面的话,在每一个方法实现前面都要加上template<class T>

2).在没有使用模板机制的类中,都是要在方法前面加上classname::。现在使用模板机制了,还要在方法前面加上classname<T>。

3.类模板非类型参数

       除了模板参数外,还有一个非类型模板参数,我们可以把它当做一个宏来用。非类型模板参数是有类型限制的。一般而言,它可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针,具体还是来看一个例子吧。

#include<iostream>
using namespace std;

template<class T,int size>
class test{
public:
T array[size];
test();
T hello(T a,T b);
};

template<class T,int size>
test<T,size>::test(){
for(int i =0;i<size;i++){
array[i]=array[i-1]+1;
}
}
template<class T,int size>
T test<T,size>::hello(T a,T b){
cout<<"hello world1"<<endl;
return a+b;
}

int main(){
test<int,10> *t = new test<int,10>();
cout<<"a+b="<<t->hello(6,8)<<endl;
for(int i;i<10;i++){
cout<<i<<"--"<<t->array[i]<<endl;
}
return 0;
}
打印结果:

hello world1

a+b=14

0--1

1--2

2--3

3--4

4--5

5--6

6--7

7--8

8--9

9--10

其实这里,我也不知道C++怎么会有这样的机制,且先不管它了,在android代码中是有见到这样用的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: