首页 > 编程语言 >C++模板的实例化

C++模板的实例化

时间:2024-03-16 13:56:56浏览次数:19  
标签:函数 int C++ 编译器 实例 Swap 模板

C++ 模板

模板并不是真正的函数或类,它仅仅是编译器用来生成函数或类的一张“图纸”。模板不会占用内存,最终生成的函数或者类才会占用内存。由模板生成函数或类的过程叫做模板的实例化,相应地,针对某个类型生成的特定版本的函数或类叫做模板的一个实例。

在学习模板以前,如果想针对不同的类型使用相同的算法,就必须定义多个极其相似的函数或类,这样不但做了很多重复性的工作,还导致代码维护困难,用于交换两个变量的值的 Swap() 函数就是一个典型的代表。而有了模板后,这些工作都可以交给编译器了,编译器会帮助我们自动地生成这些代码。从这个角度理解,模板也可以看做是编译器的一组指令,它命令编译器生成我们想要的代码。

模板的实例化是按需进行的,用到哪个类型就生成针对哪个类型的函数或类,不会提前生成过多的代码。也就是说,编译器会根据传递给类型参数的实参(也可以是编译器自己推演出来的实参)来生成一个特定版本的函数或类,并且相同的类型只生成一次。实例化的过程也很简单,就是将所有的类型参数用实参代替。

例如,给定下面的函数模板和函数调用:

template<typename T> void Swap(T &a, T &b){
    T temp = a;
    a = b;
    b = temp;
}
int main(){
    int n1 = 100, n2 = 200, n3 = 300, n4 = 400;
    float f1 = 12.5, f2 = 56.93;
    Swap(n1, n2);  //T为int,实例化出 void Swap(int &a, int &b);
    Swap(f1, f2);  //T为float,实例化出 void Swap(float &a, float &b);
    Swap(n3, n4);  //T为int,调用刚才生成的 void Swap(int &a, int &b);
    return 0;
}

编译器会根据不同的实参实例化出不同版本的 Swap() 函数。对于Swap(n1, n2)调用,编译器会生成并编译一个 Swap() 版本,其中 T 被替换为 int:

void Swap(int &a, int &b){
    int temp = a;
    a = b;
    b = temp;
}

对于Swap(f1, f2)调用,编译器会生成另一个 Swap() 版本,其中 T 被替换为 float。对于Swap(n3, n4)调用,编译器不会再生成新版本的 Swap() 了,因为刚才已经针对 int 生成了一个版本,直接拿来使用即可。

另外需要注意的是类模板的实例化,通过类模板创建对象时并不会实例化所有的成员函数,只有等到真正调用它们时才会被实例化;如果一个成员函数永远不会被调用,那它就永远不会被实例化。这说明类的实例化是延迟的、局部的,编译器并不着急生成所有的代码。

通过类模板创建对象时,一般只需要实例化成员变量和构造函数。成员变量被实例化后就能够知道对象的大小了(占用的字节数),构造函数被实例化后就能够知道如何初始化了;对象的创建过程就是分配一块大小已知的内存,并对这块内存进行初始化。

请看下面的例子:

#include <iostream>
using namespace std;

template<class T1, class T2>
class Point{
public:
    Point(T1 x, T2 y): m_x(x), m_y(y){ }
public:
    T1 getX() const{ return m_x; }
    void setX(T1 x){ m_x = x; }
    T2 getY() const{ return m_y; };
    void setY(T2 y){ m_y = y; };
    void display() const;
private:
    T1 m_x;
    T2 m_y;
};

template<class T1, class T2>
void Point<T1, T2>::display() const  {cout<<"x="<<m_x<<", y="<<m_y<<endl;}

int main(){
    Point<int, int> p1(10, 20);  //要指明类型
    p1.setX(40);
    p1.setY(50);
    cout<<"x="<<p1.getX()<<", y="<<p1.getY()<<endl;
    Point<char*, char*> p2("东180度", "北210度");
    p2.display();
    return 0;
}

 

运行结果:

x=40, y=50
x=东180度, y=北210度


p1 调用了所有的成员函数,整个类会被完整地实例化。p2 只调用了构造函数和 display() 函数,剩下的 get 函数和 set 函数不会被实例化。

值得提醒的是,Point<int, int>Point<char*, char*>是两个相互独立的类,它们的类型是不同的,不能相互兼容,也不能自动地转换类型,所以诸如p1 = p2;这样的语句是错误的,除非重载了=运算符。

标签:函数,int,C++,编译器,实例,Swap,模板
From: https://www.cnblogs.com/uacs2024/p/18077007

相关文章

  • C++模板中的非类型参数
    C++模板模板是一种泛型技术,目的是将数据的类型参数化,以增强C++语言(强类型语言)的灵活性。C++对模板的支持非常自由,模板中除了可以包含类型参数,还可以包含非类型参数,例如:template<typename T, int N> class Demo{ };template<class T, int N> void func(T (&arr)......
  • C++示例:学习C++标准库,std::unordered_map无序关联容器的使用
    01std::unordered_map介绍std::unordered_map是C++标准库中的一种无序关联容器模板类,它提供了一种将键映射到值的方法。它的底层基于哈希表实现,内容是无序的,可以在平均情况下在O(1)的时间复杂度内完成插入、查找和删除操作。值得注意的是,哈希表可能存在冲突,即不同的键值......
  • nodejs打包问题解决实例
    node命令集合npmsetregistryhttps://registry.npm.taobao.org/npmconfigsetregistryhttps://registry.npmjs.org/npmconfigsetsass_binary_sitehttps://npm.taobao.org/mirrors/node-sass/npmgetregistry //npm安装包的提示操作目录权限不足npmconfigsetu......
  • 基于EP4CE6F17C8的FPGA数码管动态显示实例
    一、电路模块1、数码管开发板板载了6个数码管,全部为共阳型,原理图如下图所示,段码端引脚为DIG[0]~DIG[7]共8位(包含小数点),位选端引脚为SEL[0]~SEL[5]共6位。端口均为低电平有效。其实物图如下所示。数码管引脚分配见下表。2、时钟晶振开发板板载了一个50MHz的有源晶振,为系统......
  • 滴水逆向笔记系列-c++总结2-36.权限控制-37.虚函数-38.多态_绑定
    第三十六课c++3权限控制1.定义和实现分开写2.private和publicprivate权限说明私有变量在类外是无法访问的,只有在类内或者使用类内函数访问类内函数访问3.private真的不能访问吗反汇编看看t对象在初始化public和private成员时都是一视同仁的,在底层还是没区别,都是编......
  • 滴水逆向笔记系列-c++总结3-39.模板-40.引用_友元_运算符重载
    第三十八课c++6模板1.冒泡排序和折半查找voidSort(int*arr,intnLength) { inti; intk; for(i=0;i<nLength-1;i++) { for(k=0;k<nLength-1-i;k++) { if(arr[k]>arr[k+1]) { inttemp=arr[k]; a......
  • 滴水逆向笔记系列-c++总结4-41.new-delete-vector-42.链表
    第四十课c++8new-delete-vector1.内存空间复习在类外函数外的变量就是全局变量,程序一编译地址就已经确定了的临时数据,参数和局部变量就是在堆栈里而使用malloc函数动态申请的则是在堆里2.跟踪调试反汇编函数我们调用malloc函数申请内存,但是不是malloc一个函数完成整个......
  • C++性能分析工具
    gprof:这是一个GNU的性能分析工具,主要用于分析程序的函数调用关系,以及每个函数的运行时间等。Valgrind:这是一个用于内存调试、内存泄漏检测以及性能分析的开源工具集。其中,Valgrind的Callgrind工具可以收集程序运行时的函数调用信息,用于性能分析。perf:这是Linux下的一个性能分析......
  • SQLiteC/C++接口详细介绍-sqlite3类(一)
    快速跳转文章列表:SQLite—系列文章目录  上一篇:SQLiteC/C++接口简介 下一篇:SQLiteC/C++接口详细介绍(二) 引言:SQLiteC/C++数据库接口是一个流行的SQLite库使用形式,它允许开发者在C和C++代码中嵌入SQLite基本功能的解决方案。通过SQLiteC/C++数据库接口,开发者可以......
  • 【C++函数速查】lower_bound和upper_bound使用方法详细解读
    文章目录1)概述2)函数使用3)案例代码1)概述lower_......