类模板总结

简介: 所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。

所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。



函数模板定义形式


 由以下三部分组成:  模板说明 + 函数定义 + 函数模板调用

 template < 类型形式参数表 >

 类型  函数名 (形式参数表)

{

   //语句序列

}


1. 模板说明  

template    < 类型形式参数表 >  


类型形式参数的形式:

typenameT1 ,  typename T2 , …… , typename Tn

class T1 ,  class T2 , …… , class Tn

(:typename 和 class 的效果完全等同)


2. 函数定义

 类型  函数名  (形式参数表)

{

}


注意:模板说明的类属参数必须在函数定义中出现一次

     函数参数表中可以使用类属类型参数,也可以使用一般类型参数



3. 函数模板调用

max<int>(a, b);  //显式类型调用

max(a, b);   //自动数据类型推导


函数模板和普通函数区别结论: 

两者允许并存

函数模板不允许自动类型转化


函数模板和普通函数在一起,调用规则:

1 函数模板可以像普通函数一样被重载

2 C++编译器优先考虑普通函数

3 如果函数模板可以产生一个更好的匹配,那么选择模板

4 可以通过空模板实参列表的语法限定编译器只通过模板匹配



结论:

1. 编译器并不是把函数模板处理成能够处理任意类型的函数

2. 编译器从函数模板通过具体类型产生不同的函数


2.类模板定义


  类模板由模板说明和类说明构成


  模板说明同函数模板,如下:


        template    <类型形式参数表>


        类声明


例如:


  template  <typename Type>


class ClassName


{

//ClassName 的成员函数


  private :


  Type DataMember;


}


1.父类一般类,子类是模板类, 和普通继承的玩法类似


2.子类是一般类,父类是模板类,继承时必须在子类里实例化父类的类型参数


3.父类和子类都时模板类时,子类的虚拟的类型可以传递到父类中


总结:


在同一个cpp 文件中把模板类的成员函数放到类的外部,需要注意以下几点


函数前声明 template    <类型形式参数表>

类的成员函数前的类限定域说明必须要带上虚拟参数列表

返回的变量是模板类的对象时必须带上虚拟参数列表

成员函数参数中出现模板类的对象时必须带上虚拟参数列表

成员函数内部没有限定

注意:当类模板的声明(.h文件)和实现(.cpp 或.hpp文件)完全分离,因为类模板的特殊实现,我们应在使用类模板时使用#include 包含 实现部分的.cpp 或.hpp文件。


类内部声明友元函数,必须写成一下形式

   template<typename T>


friend A<T> addA (A<T> &a, A<T> &b);


友元函数实现 必须写成

template<typename T>


 A<T> add(A<T> &a, A<T> &b)


{

//......


}


友元函数调用 必须写成

A<int> c4 = addA<int>(c1, c2);


总结:


  • 从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个static数据成员
  • 和非模板类的static数据成员一样,模板类的static数据成员也应该在文件范围定义和初始化
  • static 数据成员也可以使用虚拟类型参数T

6.类模板使用总结

归纳以上的介绍,可以这样声明和使用类模板:


1) 先写出一个实际的类。


2) 将此类中准备改变的类型名(如int要改变为float或char)改用一个自己指定的虚拟类型名(如上例中的T)。


3) 在类声明前面加入一行,格式为:


   template <typename 虚拟类型参数>


如:


   template <typename numtype>


   class A


   {…}; //类体


4) 用类模板定义对象时用以下形式:


   类模板名<实际类型名> 对象名;


   或 类模板名<实际类型名> 对象名(实参表列);


如:


   A<int> cmp;


   A<int> cmp(3,7);


5) 如果在类模板外定义成员函数,应写成类模板形式:


  template <typename 虚拟类型参数>


  函数类型 类模板名<虚拟类型参数>::成员函数名(函数形参表列) {…}


关于类模板的几点补充


1) 类模板的类型参数可以有一个或多个,每个类型前面都必须加typename 或class,如:


   template <typename T1,typename T2>


   class someclass


   {…};


在定义对象时分别代入实际的类型名,如:


   someclass<int, char> object;


2) 和使用类一样,使用类模板时要注意其作用域,只有在它的有效作用域内用使用它定义对象。


3) 模板类也可以有支持继承,有层次关系,一个类模板可以作为基类,派生出派生模板类。


代码如下:

main.h

#include "Vector.cpp"
#include <iostream>
#include <Windows.h>
class Student
{
public:
  Student(const char* _name, int _age)
  {
    strcpy_s(name, 64, _name);
    age = _age;
  }
  ~Student()
  {
  }
  Student()
  {
    age = 0;
    name[0] = NULL;
  }
  friend ostream& operator<<(ostream& os, const Student& object);
private:
  char name[64];
  int age;
};
int main(void)
{
  Vector<int> studentVector(10);
  for (int i = 0; i < studentVector.getLength(); i++)
  {
    studentVector[i] = i;
  }
  //依次序打印
  for (int i = 0; i < studentVector.getLength(); i++)
  {
    cout << studentVector[i] << endl;
  }
  //全部打印
  cout << studentVector << endl;
  //float类型
  Vector<float> studentVector1(10);
  for (int i = 0; i < studentVector1.getLength(); i++)
  {
    studentVector1[i] = i * 0.1f;
  }
  //依次序打印
  for (int i = 0; i < studentVector1.getLength(); i++)
  {
    cout << studentVector1[i] << endl;
  }
  //全部打印
  cout << studentVector1 << endl;
  Student s1("李小双", 28);
  Student s2("俩后", 40);
  Vector<Student> studentVector3(2);
  studentVector3[0] = s1;
  studentVector3[1] = s2;
  //依次序打印
  for (int i = 0; i < studentVector3.getLength(); i++)
  {
    cout << studentVector3[i] << endl;
  }
  //整体打印
  cout << studentVector3 << endl;
  system("pause");
  return 0;
}
ostream& operator<<(ostream& os, const Student& object)
{
  os << "姓名:" << object.name << "年龄:" << object.age << endl;
  return os;
}

Vector.h

#include <iostream>
using namespace std;
template <typename T>
class Vector
{
public:
  template <typename T>
  friend ostream& operator<< <T> (ostream& os, const Vector<T>& object);
public:
  Vector(int m_len=128);
  ~Vector();
  Vector(const Vector& object);
  int getLength();
  T& operator[](int i);
  Vector& operator=(const Vector& object);
private:
  int m_len;
  T* m_size;
};
template <typename T>
ostream& operator<<(ostream& os, const Vector<T>& object);

Vector.cpp

#include "Vector.h"
template <typename T>
Vector<T>::Vector<T>(int size)
{
  this->m_len = size;
  //分配内存大小
  this->m_size = new T[m_len];
}
template <typename T>
Vector<T>::~Vector()
{
  if (m_size != NULL)
  {
    delete[] m_size;
    m_size = NULL;
    m_len = 0;
  }
}
template <typename T>
int Vector<T>::getLength()
{
  return m_len;
}
template <typename T>
ostream& operator<<(ostream& os, const Vector<T>& object)
{
  for (int i = 0; i < object.m_len; i++)
  {
    os << object.m_size[i] << endl;
  }
  return os;
}
template <typename T>
T& Vector<T>::operator[](int i)
{
  return m_size[i];
}
template <typename T>
Vector<T>::Vector<T>(const Vector<T>& object)
{
  if (m_size != NULL)
  {
    delete[] m_size;
    m_size = NULL;
    m_len = 0;
  }
  //分配内存
  this->m_len = object.m_len;
  this->m_size = new T[this->m_len];
  //赋值
  for (int i = 0; i < object.m_len; i++)
  {
    this->m_size[i] = object.m_size[i];
  }
}
//赋值构造函数
template <typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& object)
{
  if (this->m_size != NULL)
  {
    delete[] m_size;
    m_len = 0;
    m_size = NULL;
  }
  this->m_len = object.m_len;
  this->m_size = new T[this->m_len];
  for (int i = 0; i < object.m_len; i++)
  {
    this->m_size[i] = object.m_size[i];
  }
}


相关文章
|
C++
60 C++ - 类模板的应用
60 C++ - 类模板的应用
33 0
|
编译器 Linux C++
59 C++ - 类模板
59 C++ - 类模板
60 0
|
4月前
|
算法 编译器 程序员
|
6月前
|
编译器 C++
39类模板
39类模板
21 0
|
11月前
|
编译器 C++
类模板的三种表达方式
类模板的三种表达方式
50 0
|
算法 编译器 C++
C++泛型编程之类模板
C++泛型编程之类模板
52 0
|
编译器 C++
C++函数模板与类模板
C++函数模板与类模板
79 0
|
编译器 C++
【C++】什么是函数模板/类模板?
1.什么是函数模板? 函数模板简单来说就是一个模板,与函数参数的类型无关,是一个模子,不是真正的函数,实例化的函数会根据实参的类型自动推导类型。
|
存储 编译器 C++
【C++要笑着学】泛型编程 | 函数模板 | 函数模板实例化 | 类模板(二)
本章将正式开始介绍C++中的模板,为了能让大家更好地体会到用模板多是件美事!我们将会举例说明,大家可以试着把自己带入到文章中,跟着思路去阅读和思考,真的会很有意思!如果你对网络流行梗有了解,读起来将会更有意思!
140 1
【C++要笑着学】泛型编程 | 函数模板 | 函数模板实例化 | 类模板(二)
|
编译器 C语言 C++
【C++要笑着学】泛型编程 | 函数模板 | 函数模板实例化 | 类模板(一)
本章将正式开始介绍C++中的模板,为了能让大家更好地体会到用模板多是件美事!我们将会举例说明,大家可以试着把自己带入到文章中,跟着思路去阅读和思考,真的会很有意思!如果你对网络流行梗有了解,读起来将会更有意思!
124 0
【C++要笑着学】泛型编程 | 函数模板 | 函数模板实例化 | 类模板(一)