C++模板的使用

目录

1、模板的概述:

2、函数模板

2.1、函数模板的定义方式

 2.2、函数模板注意事项

2.3、函数模板和普通函数区别

2.4、函数模板的重载

2.5、函数模板的非类型参数

2.6、多文件编程实现函数模板

3、类模板

3.1、类模板的定义

3.2、类模板和函数模板区别

3.3、类模板的友元函数

3.4、类模板的继承

3.5、类模板对象作为函数参数


1、模板的概述:

        C++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。C++提供两种模板机制:函数模板和类模板。
总结:
C++面向对象编程思想:封装、继承、多态
C++泛型编程思想:模板
模板的分类:函数模板、类模板
将功能相同,类型不同的函数(类)的类型抽象成虚拟的类型。当调用函数(类实例化对象)的时候,编译器自动将虚拟的类型具体化。这个就是函数模板(类模板)。 

2、函数模板


2.1、函数模板的定义方式

关键字:template

#include 
#include 

using namespace std;
template 
void swap_all(T&x,T&y)        //函数作用:通过使用函数模板交换任意类型的变量的值
{
    T temp = x;
    x = y;
    y = temp;
}

int main()

{

        int a = 10,b = 20;

        swap(a,b);        //隐式类型推导

        //swap(a,b);        //显示类型推导(推荐使用)

        cout << "a = " < 2.2、函数模板注意事项

        (1)显示类型推导参数和推导的类型必须一致。
        (2)如果有普通函数和模板函数都能匹配优先调用模板函数,如在调用时用显示调用(省略类型的方式  swap_all<>(1,2))则会调用模板函数。

2.3、函数模板和普通函数区别

    (1)函数只可以有一种数据类型相匹配,模板有多种类型相匹配
    (2)隐式推导优先使用普通函数,只有普通函数不匹配才使用函数模板
    (3)函数模板只有在调用时,才会构建函数,而普通函数是在编译时。
    (4)普通函数调用时候可以发生自动类型转换,而函数模板不行。  

2.4、函数模板的重载

        和普通函数的重载相似。也是同一个作用域类函数名相同参数列表不同。
        以下是参数顺序不同的重载:      

    template void swap1(T2 a,T1 b)
    template void swap1(T1 a,T2 b)

         注意,在函数参数顺序不同的重载中,实例化的时候不可以是相同类型。
        例如  swap1(1,2)则没法匹配哪个函数。
     以下是参数个数不同的重载
         template   void swap1(T1 a,T2 b)
         template  void swap1(T2 t)
         传入不同的参数,调用不同的版本

2.5、函数模板的非类型参数

     希望传入函数一个特定的确定参数,但不希望放在小括号中。可以通过非类型参数实现。在模板<>中加了一个参数,但这个参数不是类型参数,是具体的某一个值。
     格式:template
               返回值 函数名(T& 变量)
      例如:template
                 void showArr(T* arr);
      注意:在上例子中,size是通过模板传入到函数中,可以当做普通变量使用
                非类型参数都是常量,在函数中不允许修改,只可以使用,定义非类型参数变量时候,需要加const。   
 例子: 写一个函数模板,打印数组的所有内容。(但不可以在参数中加入数组大小)。

template
void show_size(Y*x)
{
    for(int i = 0;i(arr);
    return 0;
}

2.6、多文件编程实现函数模板

        在定义函数或者类的时候,会.h和cpp文件,定义和申明分开。但是在C++中使用模板这样做会出现连接错误,原因:函数模板是在调用时确定的版本,而调用时.h中没有函数实现,出现连接错误,找不到函数体,如果分开后,编译会出现连接错误。

解决方法:

     (1)在main中#include  和 #include
     (2)模板的定义和申明都放在.h头文件中。

3、类模板

3.1、类模板的定义

     建立一个通用的类,如果希望成员变量的类型是任意的,可以用类模板实现。类模板不是一个实际的类型,是虚拟的,和ppt模板一样,实例化的时候才会构建类。
     格式:template
               class test { T age; };
      实例化: 类名<类型> 变量名(参数);
代码如下:

template 
class person
{
private:
    t1 a;
    t2 b;
public:
    person();
    person(t1 a,t2 b);

};

template 
person::person()
{
   a = 0;
   b = 0;
}
template 
person::person(t1 a, t2 b)
{
    this->a = a;
    this->b = b;
}



int main(int argc, char *argv[])
{
    person p1(10,'a');

    return 0;
}

     

3.2、类模板和函数模板区别

        函数模板可以使用隐式类型推导,但类模板不可以,必须显示推导
      类模板在定义template时候,可以加上默认参数。template
      在模板中的默认参数类型中,如果所有模板参数都是缺省,但在类进行实例化的时候,尖括号不可以省略

3.3、类模板的友元函数

using namespace std;
template 
class person
{
private:
    t1 a;
    t2 b;
public:
    person();
    person(t1 a,t2 b);
    template 
    friend void show_person(person &ob);

};

template 
person::person()
{
   a = 0;
   b = 0;
}
template 
person::person(t1 a, t2 b)
{
    this->a = a;
    this->b = b;
}

template 
void show_person(person &ob)        //函数模板做为类模板的友元函数
{
    cout< p1(10,'a');
    show_person(p1);    //函数模板作为类模板的友元函数的调用
    
    return 0;
}

3.4、类模板的继承

        普通类继承:class son:public father{}
        模板类继承:普通子类继承模板类;
        格式:class 子类:public 父类<指定类型>
        构建对象:和普通对象的构建一样 类名 对象(参数列表);
 
         类模板继承类模板
         格式: template
                     class son: public person {}

当类模板碰到继承时,需要注意以下几点:

(1)当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型

(2)如果不指定,编译器无法给子类分配内存

(3)如果想灵活指定出父类中T的类型,子类也需为类模板

//类模板与继承
template
class Base
{
	T m;
};

//class Son: public Base //错误,必须要知道父类中的T类型,才能继承给子类
class Son :public Base
{

};

void test01()
{
	Son s1;
}

//如果想灵活指定父类中T的类型,子类也需要变成类模板
template
class Son2 : public Base
{
public:
	Son2()
	{
		cout << "T1的类型为:" << typeid(T1).name() << endl;
		cout << "T2的类型为:" << typeid(T2).name() << endl;

	}
	T1 obj;
};

void test02()
{
	Son2 s2;
}

int main()
{
	test02();
	
	system("pause");
	return 0;
}

3.5、类模板对象作为函数参数

一共有三种传入方式:

        (1)指定传入的类型:直接显示对象的数据类型

        (2)参数模板化:将对象中的参数变为模板进行传递

        (3)整个类模板化:将这个对象类型模板化进行传递

示例

//类模板对象做函数参数
template
class Person
{
public:
	Person(T1 name,T2 age)
	{
		this->m_Age = age;
		this->m_Name = name;
	}

	void showPerson()
	{
		cout << "name: " << this->m_Name << " age:" << this->m_Age << endl;
	}

	T1 m_Name;
	T2 m_Age;
};

//1、指定传入类型
void printPerson1(Person&p)
{
	p.showPerson();
}
void test01()
{
	Personp("孙悟空", 199);
	printPerson1(p);
}

   
// 2、参数模板化
template
void printPerson2(Person&p)
{
	p.showPerson();
	cout << "T1的类型为:" << typeid(T1).name() << endl;
	cout << "T2的类型为:" << typeid(T2).name() << endl;
}
void test02()
{
	Personp("猪八戒", 90);
	printPerson2(p);
}

// 3、整个类模板化
template
void printPerson3(T &p)
{
	p.showPerson();
	cout << "T的类型为:" << typeid(T).name() << endl;
}
void test03()
{
	Personp("唐僧", 60);
	printPerson3(p);
}

int main()
{
	test01();
	test02();
	test03();
	system("pause");
	return 0;
}

你可能感兴趣的:(c++)