c++学习之模板

简介: c++学习之模板

一,模板的概述

c++提供了函数模板(function template),即建立一个通用的函数,不具体定义函数的参数类型以及函数类型,以他为模板。与该函数功能相同的函数我们定义时,直接利用模板,不必重新定义,大大提高了写代码的效率,其次根据模板定义不同的参数的类型以及函数的类型,实现函数不同的功能。总的来说,C++中的模板是一种支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。C++程序由类和函数组成,模板也分为类模板和函数模板。

这也是c++泛型编程思想:模板。

二,函数模板

1.函数模板的定义

关键字 template

99d28501745541eda2f89da4eda7832e.png

802a62e007d94b7a8ba84dfc4ad3b20f.png

c++提供了关键字tmplate用来实现模板类型的虚拟化,在调用模板时,编译器会自动地将虚拟的类型具体化,对于函数类型,就是函数模板,对于类的抽象化类型,就是类模板

在这里我们还会用到typename 也是一个关键字,专门用来表示函数模板中的类型

9fbd1a047e4640169fce9ee69cef4896.png

例如:

/利用template将T抽象成一个虚拟类型,即T认为是一个类型
//以交换函数来举例  
template<typename T> void myswap(T &x, T &y)//该类型抽象只作用该函数
{
  T tmp = x;
  x = y;
  y = tmp;
}
//再调用函数模板时,会自动将虚拟类型具体化
int main()
{
  int a = 10; int b = 20;
  myswap(a, b);//函数调用时会根据参数类型自动推导出T是哪一个类型
  cout << a << " " << b << endl;
   //20 10
  return 0;
}

可以看到函数模板在面对不同的参数类型都可以实现函数功能,展现了函数模板的多功能。

函数模板会被编译器编译两次:

第一次编译:对函数模板本身编译,即将函数源代码转化为机器码:预处理阶段。

第二次编译:函数调用处将T的类型具体化。

对于实例化过程:

C++ 函数模板中的类型具体化是在函数编译的过程中完成的,当使用函数模板创建一个具体类型的函数时,编译器会根据实际参数的类型来生成对应的函数代码,这个过程也被称为模板类或模板函数的实例化。在实例化时,编译器会将函数模板中的类型参数具体化为实际的类型,同时在编译器内部生成对应的代码。

需要注意的是,C++ 中的函数模板并不是一种动态类型或者泛型编程的方式,而是一种静态的模板化机制。因此,在编译阶段,编译器会将模板代码生成为具体的函数代码,以提高代码的效率和可靠性。

函数模板目标:模板是为了实现泛型,可以减轻编程的工作量,增强函数的重用性。

2.函数模板的注意事项

1.对于函数模板与普通函数,在函数调用时,函数时会优先选择普通函数。

如下图:函数在调用时优先选择普通函数


4078e6f815184e2bab960625ce5fa8e8.png

2.普通函数和模板函数,像调用函数模板只能强制使用函数模板。

在调用时函数名与参数中间添加<>,表示强制调用函数模板。


eb707724a1f7458b86970786ea91216b.png

当然我们也可以改变其中的类型<double>,强制调用模板类型为double。

3.函数模板自动类型推导时,不能对函数的参数进行自动类型转换。

template<typename T>
void print(T a, T b)
{
  cout << a << b << endl;
  cout << "函数模板" << endl;
}
int main()
{
  int a = 10; char b = 'c';
  print(a, b);
}

类型不相同就不会调用,这里编译器会自动报错。

3.函数模板的重载

函数模板也可以同名,根据函数的参数以及雷响,在调用会自动调用对应的模板,也就是函数模板的重载。

template<typename T> void myprint(T a, T b)
{
  cout << a << b << endl;
  cout << "调用双参数模板" << endl;
}
template<typename T> void myprint(T a)
{
  cout << a  << endl;
  cout << "调用单参数模板" << endl;
}
int main()
{
  int a = 10;
  myprint(a);
  return 0;
}

4.函数模板的局限性

对于函数模板,这里的函数类型都是编译器认识的的,倘若遇到自定义类型如结构体或类时,该类型函数模板无法识别,函数无法实现其功能。解决办法如下:

一,一般是将运算符重载。

template<typename T> void myprint (T a)
{
  cout << a << endl;
}
class Data
{
  friend ostream& operator<<(ostream& out, Data x);
public:
  Data(int x)
  {
    data= x;
  }
  ~Data(){}
private:
  int data;
};
ostream& operator<<(ostream& out, Data x)
{
  out << x.data;
  return out;
}
template<typename T> void myprint(T a)
{
  cout << a << endl;
}
int main()
{
  Data x(10);
  int a = 10;
  myprint(a);
  myprint(x);//需将函数里的所有运算符重载
  return 0;
}

二,具体化函数模板

再写函数模板,将之前的函数模板的类型删掉,重新具体实现函数模板的类型以及参数以及函数实现。

template<typename T> void myprint (T a)
{
  cout << a << endl;
}
class Data
{
  friend void myprint<Data>(Data a);
public:
  Data(int x)
  {
    data= x;
  }
  ~Data(){}
private:
  int data;
};
//具体实例化模板
template<> void myprint<Data>(Data a)
{
  cout << a.data << endl;
}
int main()
{
  Data x(10);
  int a = 10;
  myprint(a);
  myprint(x);//需将函数里的运算符重载
  return 0;
}

三,类模板

1.类模板的概念

与函数模板的概念相类似,有时有两个类或多个类的功能是大体相同的,仅仅因为数据类型不一样,于是乎c++提供了函数模板近似的类模板,用于实现所需数据的类型参数化。

2.类模板定义方式

类模板定义方式如下:

//类模板
//这里的类型就不用typename,为了区分模板,这里就用class表示类
template<class T1, class T2> class Data
{
private:
T1 a;
T2 b;
public:
Data(){}
Data(T1 a, T2 b)
{
this->a = a;
this->b = b;
}
void showData()
{
cout<<a<<" "<<b<<endl;
}
};

对于类模板,在实例化对象时,不能自动推导类型:

int main()
{
  //不能这样定义
  //Data obj(10,20);
  //在实例化对象时,是无法自动推导出类中数据类型,需要标明
  Data<int,int >obj(10, 20);
  obj.showData();
  return 0;
}

3.类模板的成员函数在类外实现

若成员函数在类外实现,则需要注意其类模板的作用域是只在类中的,而成员函数在类外定义时就需要重新在成员函数前定义类模板。

//类模板
template<class T1, class T2> class Data
{
private:
T1 a;
T2 b;
public:
Data(){}
Data(T1 a, T2 b);
void showData();
};
template<class T1, class T2>Data<T1,T2>::Data(T1 a, T2 b)
{
this->a = a;
this->b = b;
}
template<class T1, class T2>void Data<T1,T2>::showData()
{
cout<<a<<" "<<b<<endl;
}

4.函数模板作为类模板的友元

函数可以作为类的友元函数,那么函数模板亦可作为类模板中友元函数模板

template<class T1, class T2>class Data
{
  template<typename T3, typename T4>friend void myPrintData(Data<T3, T4>& ob);//声明为友元
private:
  T1 a;
  T2 b;
public:
  Data() {}
  Data(T1 a, T2 b)
  {
    this->a = a;
    this->b = b;
  }
};
//函数模板
template<typename T3, typename T4> void myPrintData(Data<T3, T4>& ob)
{
  cout << ob.a << " " << ob.b << endl;
}
int main()
{
  Data<int, char> ob1(100, 'A');
  myPrintData(ob1);
}

在函数模板定义中我们可以看到其参数为类,而我们这里是类模板,故参数是需要实例化类的对象,其次需要引用代表对对象的操作。

其次还需要注意设置友元时,其中的template虚拟的类型也需要紧跟。

其中类中的数据类型在这里是所定义的类模板的类型。

5.在写程序时模板的头文件与源文件分离时的问题。

头文件定义类模板.

源文件中实现类中的成员函数(注意需加上数据类型)。如:

template<class T1,class T2> Data<T1,T2>::Data()
{
....
};

其次在主函数文件实例化对象时进行两次编译,第一次编译在预处理阶段,在头文件,编译类或函数本身,第二次编译在源文件中推导类型或指明类型,可是此时之前第一次编译类中的数据以及成员函数找不到了,第二次无法调用无法具体化并实现函数。

记得包含上源文件主函数才会通过。


相关文章
|
2月前
|
编译器 C++
【C++】——初识模板
【C++】——初识模板
33 1
【C++】——初识模板
|
2月前
|
算法 C语言 C++
C++语言学习指南:从新手到高手,一文带你领略系统编程的巅峰技艺!
【8月更文挑战第22天】C++由Bjarne Stroustrup于1985年创立,凭借卓越性能与灵活性,在系统编程、游戏开发等领域占据重要地位。它继承了C语言的高效性,并引入面向对象编程,使代码更模块化易管理。C++支持基本语法如变量声明与控制结构;通过`iostream`库实现输入输出;利用类与对象实现面向对象编程;提供模板增强代码复用性;具备异常处理机制确保程序健壮性;C++11引入现代化特性简化编程;标准模板库(STL)支持高效编程;多线程支持利用多核优势。虽然学习曲线陡峭,但掌握后可开启高性能编程大门。随着新标准如C++20的发展,C++持续演进,提供更多开发可能性。
49 0
|
3月前
|
程序员 C++
C++模板元编程入门
【7月更文挑战第9天】C++模板元编程是一项强大而复杂的技术,它允许程序员在编译时进行复杂的计算和操作,从而提高了程序的性能和灵活性。然而,模板元编程的复杂性和抽象性也使其难以掌握和应用。通过本文的介绍,希望能够帮助你初步了解C++模板元编程的基本概念和技术要点,为进一步深入学习和应用打下坚实的基础。在实际开发中,合理运用模板元编程技术,可以极大地提升程序的性能和可维护性。
|
6天前
|
存储 算法 程序员
C++ 11新特性之可变参数模板
C++ 11新特性之可变参数模板
15 0
|
2月前
|
编译器 C++
【C++】模板初级
【C++】模板初级
|
2月前
|
安全 编译器 C++
【C++】模板进阶
【C++】模板进阶
|
2月前
|
并行计算 测试技术 开发工具
【简历模板】c/c++软件工程师
【简历模板】c/c++软件工程师
51 0
|
3月前
|
安全 编译器 C++
C++一分钟之-模板元编程实例:类型 traits
【7月更文挑战第15天】C++的模板元编程利用编译时计算提升性能,类型traits是其中的关键,用于查询和修改类型信息。文章探讨了如何使用和避免过度复杂化、误用模板特化及依赖特定编译器的问题。示例展示了`is_same`类型trait的实现,用于检查类型相等。通过`add_pointer`和`remove_reference`等traits,可以构建更复杂的类型转换逻辑。类型traits增强了代码效率和安全性,是深入C++编程的必备工具。
55 11
|
3月前
|
编译器 C++ 容器
C++一分钟之-可变模板参数与模板模板参数
【7月更文挑战第21天】C++的模板实现泛型编程,C++11引入可变模板参数和模板模板参数增强其功能。可变模板参数(如`print`函数)用于处理任意数量的参数,需注意展开参数包和递归调用时的处理。模板模板参数(如`printContainer`函数)允许将模板作为参数,需确保模板参数匹配和默认值兼容。这些特性增加灵活性,但正确使用是关键。
45 4
|
3月前
|
Java 编译器 Linux
【c++】模板进阶
本文详细介绍了C++中的模板技术,包括非类型模板参数的概念、如何使用它解决静态栈的问题,以及模板特化,如函数模板特化和类模板特化的过程,以提升代码的灵活性和针对性。同时讨论了模板可能导致的代码膨胀和编译时间增加的问题。
26 2
下一篇
无影云桌面