首页 > 编程语言 >C++ 模板的笔记1

C++ 模板的笔记1

时间:2024-02-18 15:46:13浏览次数:30  
标签:函数 int void 笔记 参数 C++ template 模板

C++模板的笔记1

C++ 函数模板

函数模板的定义

函数模板是一种可以生成不同类型函数的函数声明。函数模板的参数类型不是固定的,而是在调用时由实参类型推导出来。

语法:

template <typename 参数列表>
函数返回值类型 函数名(参数列表) {
  函数体
}

示例:

template <typename T>
void swap(T& a, T& b) {
  T temp = a;
  a = b;
  b = temp;
}

该模板定义了一个名为 swap 的函数,该函数可以交换任意类型的两个变量。

函数模板的调用和参数推导

调用函数模板时,编译器会根据实参类型推导出模板参数类型。

示例:

int x = 1, y = 2;
swap(x, y); // 模板参数推导为 int

double a = 3.14, b = 2.71;
swap(a, b); // 模板参数推导为 double

函数模板的实现原理

函数模板的实现原理是:编译器会根据模板参数类型生成具体的函数代码,然后将该代码插入到程序中。

示例:

template <typename T>
void swap(T& a, T& b) {
  T temp = a;
  a = b;
  b = temp;
}

// 编译器会生成以下两个函数:

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

void swap(double& a, double& b) {
  double temp = a;
  a = b;
  b = temp;
}

函数模板的重载

函数模板可以重载,即可以定义多个具有相同名称的函数模板,但它们的模板参数列表不同。

示例:

template <typename T>
void swap(T& a, T& b) {
  // ...
}

template <typename T, typename U>
void swap(T& a, U& b) {
  // ...
}

第一个 swap 模板可以用于交换相同类型的两个变量,而第二个 swap 模板可以用于交换不同类型的两个变量。

函数模板的参数默认值

函数模板的参数可以设置默认值,如果在调用函数模板时没有指定参数类型,则使用默认值。

语法:

template <typename T = 默认值>
void 函数名(参数列表) {
  // ...
}

示例:

template <typename T = int>
void swap(T& a, T& b) {
  // ...
}

该模板中,T 的默认值为 int

如果调用 swap 函数时没有指定参数类型,则编译器会将 T 推导为 int

int x = 1, y = 2;
swap(x, y); // T 推导为 int

函数模板的泛化和特化

函数模板的泛化是指:函数模板可以用于处理不同类型的数据。

函数模板的特化是指:针对特定的类型,可以提供更具体的实现。

语法:

template <typename T>
void 函数名(参数列表) {
  // 通用实现
}

template <>
void 函数名<特化类型>(参数列表) {
  // 特化实现
}

示例:

template <typename T>
void print(T value) {
  cout << value << endl;
}

// 对 int 类型进行特化
template <>
void print(int value) {
  cout << "int: " << value << endl;
}

该模板中,print 函数针对 int 类型进行了特化,提供了更具体的实现。

调用 print 函数时,会根据实参类型选择不同的实现。

int x = 1;
print(x); // 输出 "int: 1"

double y = 3.14;
print(y); // 输出 "3.14"

C++ 类模板

类模板的定义

类模板是一种可以生成不同类型类的类声明。类模板中的成员函数和成员变量的类型不是固定的,而是在类实例化时由实参类型推导出来。

语法:

template <typename 参数列表>
class 类名 {
  // 类成员声明
};

示例:

template <typename T>
class Point {
 public:
  T x;
  T y;

  Point(T x, T y) {
    this->x = x;
    this->y = y;
  }

  void print() {
    cout << "(" << x << ", " << y << ")" << endl;
  }
};

该模板定义了一个名为 Point 的类,该类可以表示任意类型的点。

类模板的调用和参数推导

在C++17以上的编译器中,调用类模板时,编译器会根据实参类型推导出模板参数类型,你如果编译器是其他C++17以下版本,必须写上参数。

示例:

Point<int> p1(1, 2); // 实例化 Point 类,模板参数推导为 int
p1.print(); // 输出 "(1, 2)"

Point<double> p2(3.14, 2.71); // 实例化 Point 类,模板参数推导为 double
p2.print(); // 输出 "(3.14, 2.71)"

类模板的编译规则

类模板的编译规则如下:

  • 类模板本身不会被编译,只有在类实例化时才会被编译。
  • 类模板中的成员函数和成员变量的类型必须是模板参数类型或其他依赖于模板参数类型的类型。

类模板的参数默认值

类模板的参数可以设置默认值,如果在实例化类模板时没有指定参数类型,则使用默认值。

语法:

template <typename T = 默认值>
class 类名 {
  // 类成员声明
};

示例:

template <typename T = int>
class Point {
 public:
  T x;
  T y;

  Point(T x, T y) {
    this->x = x;
    this->y = y;
  }

  void print() {
    cout << "(" << x << ", " << y << ")" << endl;
  }
};

该模板中,T 的默认值为 int

在C++17以上的编译器中,如果在实例化 Point 类时没有指定参数类型,则编译器会将 T 推导为 int

Point p1(1, 2); // T 推导为 int
p1.print(); // 输出 "(1, 2)"

类模板的泛化与特化

类模板的泛化是指:类模板可以用于表示不同类型的數據。

类模板的特化是指:针对特定的类型,可以提供更具体的实现。

语法:

template <typename T>
class 类名 {
  // 通用实现
};

template <>
class 类名<特化类型> {
  // 特化实现
};

示例:

template <typename T>
class Number {
 public:
  T value;

  Number(T value) {
    this->value = value;
  }

  void print() {
    std::cout << value << std::endl;
  }
};

// 对 int 类型进行特化
template <>
class Number<int> {
 public:
  int value;

  Number(int value) {
    this->value = value;
  }

  void print() {
    std::cout << "int: " << value << std::endl;
  }
};

该模板中,Number 类针对 int 类型进行了特化,提供了更具体的实现。

调用 Number 类的 print 函数时,会根据实参类型选择不同的实现。

Number<int> n1(1);
n1.print(); // 输出 "int: 1"

Number<double> n2(3.14);
n2.print(); // 输出 "3.14"

类模板的成员函数模板

示例解析:

  • 该代码定义了一个名为 Num 的类模板,该类模板可以表示任意类型的数字。
  • Num 类模板有两个成员函数模板:show1show2show3
  • show1 函数模板可以接受任意类型的参数。
  • show2 在外部实现的,函数模板可以接受任意类型的参数。
  • show3 函数模板的参数类型必须与类模板的参数类型相同,并且特例化成int类型。

代码示例:

#include <iostream>
using namespace std;
template <typename T>
class Num{
public:
	template <typename T2> //成员方法模板泛化,类内部实现
	void show1(T2 data){
	cout<<"show1"<<endl;
	}
	template <typename T3> //成员方法模板泛化,类外实现
	void show2(T3 data);
	
	void show3(int  data);//成员方法特化,类外实现
	 
};
template <typename T>
template <typename T3>
void Num<T>::show2(T3 data)
{cout<<"show2"<<endl;}

template <typename T>
void Num<T>::show3(int data)
{cout<<"show3"<<endl;}

int main()
{
 Num<int> n;
n.show1(1);
n.show2<double>(2);
n.show3(0);
return 0;
}

知识点:

  • 类模板可以拥有成员函数模板。
  • 成员函数模板的参数可以与类模板的参数相同或不同。
  • 成员函数模板的定义需要在类模板的声明之后。
  • 成员函数模板的实现在类模板的外部需要加上,格式:
template <typename T>
template <typename T3>
返回类型 类名<T>::方法(模板参数类型 参数){}
  • 类模板可以拥有特化版成员函数模板,格式:
template <typename T>
返回类型 类名<T>::方法(指定的参数类型 参数){}
  • 类模板的成员函数不能声明为虚函数,C++ 标准规定:类模板的成员函数不能声明为虚函数,这是因为虚函数需要在运行时进行动态绑定,而类模板在编译时无法确定具体的类型。
template <typename T4>
virtual void show4(T4 data){}
//这个代码是错误的,编译会出错

拷贝构造函数模板

代码示例:

#include <iostream>

template <typename T1>
class C{
public:
	C(){
	std::cout<<"without parameters"<<std::endl;
	}
	//模板拷贝构造函数 
	template<class T2>
	C(const C<T2> &c2){
	std::cout<<"template copy constructor"<<std::endl;
	}
	//模板拷贝赋值操作符重载
	template<class T3>
	C<T1> & operator=(const C<T3> &c3)
	{
		std::cout<<"template copy assignment"<<std::endl;
		return *this;
	}
};

int main()
{
C<int> c;    //这里是无参数默认构造 输出without parameters
//C<int> c2(c); //这里没有拷贝构造 无输出 ,因为这里c2的模板参数和c一样
//c=c2;       //这里没有拷贝赋值 无输出 ,因为这里c2的模板参数和c一样
C<double> c2(c);  //这里发生了拷贝构造 输出template copy constructor
c=c2;    //这里发生了拷贝赋值 template copy assignment
return 0;
}

知识点:

  • 两个模板参数相同的时候,调用无参数默认构造
  • 两个模板参数不相同的时候,才会调用模板拷贝构造方法和拷贝赋值操作符

标签:函数,int,void,笔记,参数,C++,template,模板
From: https://www.cnblogs.com/AndreaDO/p/18018954

相关文章

  • 怎么在电脑上做工作笔记?电脑桌面电子笔记软件
    在繁忙的职场中,随时随地记录工作笔记是许多职场人士的日常需求。这不仅包括了会议记录、项目进展,还有一些灵感、规划和工作要点,都需要随手记下,以便随时查看和回顾。那么我们如何在电脑上做工作笔记更高效、便捷呢?在电脑上做工作笔记,使用一款电脑桌面电子笔记软件能够事半功倍。那......
  • 【c&c++】cJSON详解
    一、JSON概述1.1JSON介绍JSON:JavaScript对象表示法(JavaScriptObjectNotation)。是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似C语音家族的习惯(包括C、C++、C#、Java、JavaScript、Perl、Python等)。这些特性使JSON......
  • 笔记平台综合对比
    cnblogs优点:非常强大的自定义功能,丰富多样的主题可供选择,当时就准备把所有笔记都迁移到cnblogs上互联网可访问,SEO也做得好,搜索引擎中可以直接搜到文章缺点:审核,写了大概20篇试水,有两篇没有过审核,ctrl+CV重新发布,还剩一篇没过审,劝退非常睿智的体系管理,刚开始使用发现光......
  • 《Boosting Document-Level Relation Extraction by Mining and Injecting Logical Ru
    代码原文地址摘要文档级关系抽取(DocRE)旨在从文档中抽取出所有实体对的关系。DocRE面临的一个主要难题是实体对关系之间的复杂依赖性。与大部分隐式地学习强大表示的现有方法不同,最新的LogiRE 通过学习逻辑规则来显式地建模这种依赖性。但是,LogiRE需要在训练好骨干网络之后,......
  • 阅读下面 C++ 代码,输出结果为()
    #include<iostream>usingnamespacestd;classbase1{private:inta,b;public:base1(inti):b(i+1),a(b){}base1():b(0),a(b){}intget_a(){returna;}intget_b(){returnb;}};intmain()......
  • C++ STL map
    map<int,string>MyMap;//下标方式key值重复进行替换MyMap[0]="233";MyMap[0]="23333";//insert方法key值重复无法插入MyMap.insert(pair<int,string>(1,"zhangsan"));MyMap.insert(pair<int,string>(1,"zhangsan2"))......
  • N叉树遍历模板
    N叉树(N-aryTree)的类型和代码模板与二叉树有些相似,但由于N叉树具有多个子节点,因此在遍历和节点定义上有所不同。以下是N叉树的类型和相应的代码模板:N叉树节点的定义:classNode:def__init__(self,val=None,children=None):self.val=valself.children......
  • 模板默写
    别到时候题会做了板子不会写……数据结构主席树ProbFHQTreap可持久化FHQTreap图论支配树Prob上下界最大/最小流带负圈的费用流数学万能欧几里德杜教筛字符串ACAMSASAMGSAM……......
  • 读十堂极简人工智能课笔记05_无监督学习
    1. 自我改善1.1. 只有学会了如何学习和改变的人,才称得上是受过教育的人1.1.1. 卡尔·罗杰斯1.2. 人工智能如果只是学习纯理论的游戏(从国际象棋和围棋到电脑游戏),其结果已然可以令人惊叹1.3. 让大多数机器人玩叠叠乐游戏(用积木搭成塔,慢慢从塔中抽出积木,然后搭在最顶上),结果......
  • 『学习笔记』莫队
    Part0.目录概念普通莫队树上莫队带修莫队Part1.概念莫队是由莫涛提出的算法。莫队算法可以解决一类离线区间询问问题,适用性极为广泛。Part2.普通莫队普通莫队主要针对于多次区间询问的问题,基于分块的思想。过程如下:先将当前区间\([l,r]\)设为\([1,0]\),再每次......