一,函数模板

1.函数模板的概念

  • C++中提供了函数模板,所谓函数模板,实际上是建立一个通用函数,其函数的返回值类型和函数的参数类型不具体指定,用一个虚拟的类型来表示。这个通用函数就被称为函数的模板。
  • 当我们在开发中,经常会遇到一些函数体实现方式类似的函数,例如交换两个字符,交换两个数字函数,这两个函数的函数体实现是一样的,凡是这样的函数,我们都可以通过函数模板的方式来只定义一次。在调用函数时,系统会根据实参的数值类型来取代模板中的虚拟类型。再代入函数体中进行计算,这样就实现了定义一个函数模板,可以实现不同功能的函数。
  • 模板把函数或者类要处理的数据类型参数化,表现为参数的多态化。
  • 模板用于表达逻辑结构相同,但具体数据类型不同的通用行为。

2.函数模板的推演

# include<iostream>
using namespace std; /* 交换两个整数 */
void myswap(int &a, int &b)
{
int tmp = ;
tmp = a;
a = b;
b = tmp;
} /* 交换两个字符 */
void myswap(char &a, char &b)
{
char tmp;
tmp = a;
a = b;
b = tmp;
}
/*
* 我们发现上面两个函数的实现逻辑结构相同,要处理的数据类型不同,
* 而函数模板恰恰是将数据类型参数的一种机制,所以此处我们在这里定义函数模板
*/
template<typename T>
void myswap(T &t1, T &t2)
{
T tmp;
tmp = t1;
t1 = t2;
t2 = tmp;
} int main()
{
int a = ;
int b = ; char c = 'C';
char d = 'D'; myswap(a, b);
myswap(c, d); cout << "a = " << a << ",b = " << b << endl;
cout << "c = " << c << ",d = " << d << endl; /* 函数模板方式来处理 */
myswap<int>(a, b);
myswap<char>(c, d); cout << "a = " << a << ",b = " << b << endl;
cout << "c = " << c << ",d = " << d << endl; return ;
}

3.函数模板的形式

  在需要抽象化成模板的函数前面添加:template <typename T1,typename T2......>,在函数体内部要处理的数据类型定义为模板参数中的抽象数据类型即可。

4.函数模板的调用方式

  • 通过显式类型调用的方式,即myswap<int>(a,b)这种形式,显式的声明要处理的数据类型。
  • 通过数据类型自动推导的方式,即myswap(a,b)这种形式,模板函数会自动匹配传入参数的数据类型。

5.普通函数和函数模板在一起时调用规则

  • 函数模板不允许自动类型转换,普通函数可以进行自动类型转换,例如char会转换成int类型。
  • 函数模板可以向普通函数那样进行重载。
  • 编译器会优先使用普通函数,然后再使用函数模板。
  • 可以通过空模板实参列表的方式限定编译器只能通过模板匹配。myswap<>(a,b)

6.C++编译器模板机制剖析

  • 编译器并不是把函数模板处理成能够处理任意类的函数。
  • 编译器通过函数模板所传递的数据类型产生不同的函数。
  • 编译器对函数模板进行两次编译,在定义函数模板的地方对代码本身进行编译,在调用的地方对参数替换后的代码进行编译。

二,类模板

1.为什么需要类模板

  类模板的含义与函数模板类似,所谓的类模板是在多个类中的逻辑操作和功能是相同的,仅仅数据的类型不同,我们将数据类型抽象化就形成了类模板。类模板通常用在数据结构和算法这一块,这样在存储数据和对数据进行操作的时候,可以抽象化要操作的数据。形成泛型编程。

2.单个类模板的语法

# include<iostream>
using namespace std; /* 定义类模板 */
template<typename T>
class A
{
private:
T t;
public:
A(T t)
{
this->t = t;
}
void setT(T t)
{
this->t = t;
}
T getT()
{
return this->t;
}
}; int main()
{
A<int> a();
int res1 = a.getT();
cout << res1 << endl; a.setT();
int res2 = a.getT();
cout << res2 << endl; return ;
}

3.继承中的类模板

# include<iostream>
using namespace std;
/* 类模板 */
template<typename T>
class Parent
{
private:
T t;
public:
Parent(T t)
{
this->t = t;
}
void getT()
{
cout << t << endl;
}
};
/* 类模板继承中的子类为普通类 */
class Child1 :public Parent<int>
{
public:
Child1(int t):Parent(t)
{ }
};
/* 类模板中继承的子类为类模板 */
template<typename T>
class Child2 :public Parent<T>
{
public:
Child2(T t) :Parent(t)
{ }
};
int main()
{
/* 子类为普通类 */
Child1 c1();
c1.getT(); /* 子类为派生类 */
Child2<char> c2('A');
c2.getT(); return ;
}

4.类模板的定义和类模板的实现不在同一个文件中

  • 类模板中的友元函数要特别注意包含<T>,否则会报错,但是实现文件中不需要包含。
  • 在使用类模板的时候,引入的头文件是.cpp而不是.h,否则友元函数重载的操作符会报错。
  • 如果存储的数据是自定义的类,需要我们把自定义的类重写拷贝构造函数和重载赋值操作符才能保证元素的正确被复制。

三,类模板的应用

1.头文件(Vector.h)

# pragma once
# include<iostream>
using namespace std; template<typename T>
class Vector
{
private:
T * space;
int size;
public:
Vector(int size = );
Vector(const Vector<T>& v);
~Vector();
public:
T& operator[](int index);
Vector<T>& operator=(Vector<T>& v);
public:
friend ostream& operator<<<T>(ostream& out, Vector<T>& v);
};

2.实现文件(Vector.cpp)

# include<iostream>
# include"Vector.h"
using namespace std; template<typename T>
Vector<T>::Vector(int size)
{
this->space = new T[size];
this->size = size;
} template<typename T>
Vector<T>::Vector(const Vector<T>& v)
{
this->space = new T[v.size];
this->size = v.size;
for (int i = ; i < v.size; i++)
{
this->space[i] = v.space[i];
}
} template<typename T>
Vector<T>::~Vector()
{
if (this->space != NULL)
{
delete[] this->space;
this->space = NULL;
this->size = ;
}
} template<typename T>
T& Vector<T>::operator[](int index)
{
return this->space[index];
}
template<typename T>
Vector<T>& Vector<T>::operator=(Vector<T>& v)
{
if (this->space != NULL)
{
delete[] this->space;
this->space = NULL;
this->size = ;
}
this->space = new T[v.size];
this->size = v.size;
for (int i = ; i < v.size; i++)
{
this->space[i] = v.space[i];
}
return *this;
} template<typename T>
ostream& operator<<(ostream& out, Vector<T>& v)
{
for (int i = ; i < v.size; i++)
{
out << v[i] << " ";
}
return out;
}

3.测试文件(Test.cpp)

# include<iostream>
# include"Vector.cpp"
using namespace std; class Student
{
private:
char * name;
int age;
public:
Student()
{
this->name = new char[];
strcpy(this->name, "");
this->age = ;
}
Student(const Student& stu)
{
this->name = new char[strlen(name) + ];
strcpy(this->name, name);
this->age = age;
}
Student(char * name, int age)
{
this->name = new char[strlen(name) + ];
strcpy(this->name, name);
this->age = age;
}
~Student()
{
if (this->name != NULL)
{
delete[] this->name;
this->name = NULL;
}
}
Student& operator=(Student& stu)
{
if (this->name != NULL)
{
delete[] this->name;
this->name = NULL;
}
this->name = new char[strlen(stu.name) + ];
strcpy(this->name, stu.name);
this->age = stu.age;
return *this;
}
friend ostream& operator<<(ostream& cout, Student& stu);
}; ostream& operator<<(ostream& cout, Student& stu)
{
cout << "name:" << stu.name << ",age:" << stu.age << endl;
return cout;
} int main()
{
Vector<int> v1(); for (int i = ; i < ; i++)
{
v1[i] = i;
}
cout << v1 << endl; Vector<int> v2(); for (int i = ; i < ; i++)
{
v2[i] = i;
}
cout << v2 << endl; v1 = v2;
cout << v1 << endl; Vector<int> v3 = v1;
cout << v3 << endl; Student t1("刘备", );
Student t2("关羽", );
Student t3("张飞", ); Vector<Student> vTeacher();
vTeacher[] = t1;
vTeacher[] = t2;
vTeacher[] = t3;
cout << vTeacher << endl; return ;
}

C++中的模板编程的更多相关文章

  1. C++ 11可变参数接口设计在模板编程中应用的一点点总结

    概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...

  2. C++模板编程中只特化模板类的一个成员函数

    模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...

  3. C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面

    C#中的函数式编程:递归与纯函数(二)   在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...

  4. C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)

    转自:https://www.cnblogs.com/zhoug2020/p/6581477.html 模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多 ...

  5. C++之模板编程

    当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对象都具有共性. 比如 数值可以增加.减少:字符串也可以增加减少. 它们的动作是相似的, 只是对象的类型不同 ...

  6. UE4 中的 C++ 编程介绍

    https://docs.unrealengine.com/latest/CHN/Programming/Introduction/index.html UE4 中的 C++ 编程介绍 Unreal ...

  7. c++ 基于Policy 的 模板编程

    在没真正接触c++  模板编程之前.真的没有想到c++ 还能够这么用.最大的感触是:太灵活了,太强大了. 最初接触模板威力还是在Delta3d中,感觉里面的模板使用实在是灵活与方便,特别是dtAI中使 ...

  8. C++中函数模板的概念和意义

    1,对泛型编程进行学习,泛型编程是实际工程开发中必用的技术,大型公司的通用 库都是采用泛型编程的技术完成的,C++ 中支持泛型编程技术,C++ 中的函数  模板和类模板就是 C++ 中泛型编程技术,本 ...

  9. C++中函数模板的深入理解

    1,函数模板深入理解: 1,编译器从函数模板通过具体类型产生不同的函数: 1,模板就是模子,通过这个模子可以产生很多的实物: 2,函数模板就是编译器用来产生具体函数的模子: 2,编译器会对函数模板进行 ...

随机推荐

  1. UIScrollView(滚动试图)

    UIScrollView(滚动试图) 1.简介 为什么有UISCrollView: 在iOS开发中,由于移动设备的屏幕大小有限,所以不能像PC一样显示很多内容,因此当手机屏幕需要展示的内容较多超出一个 ...

  2. swift开发网络篇 - 用户登录POST JSON and header

    版权声明:本文为博主原创文章,未经博主允许不得转载. import UIKit import Alamofire class ViewController: UIViewController { va ...

  3. vue学习笔记二:v-if和v-show的区别

    v-if vs v-show v-if 是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建. v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做—— ...

  4. [转]在Win7 64位注册ActiveX控件

    原文作者: K_H_H 原文地址: http://blog.sina.com.cn/s/blog_56b96c5a0100ztc7.html  首先必须以管理员身份运行cmd.exe,即在cmd.ex ...

  5. thinkphp3.2.3 小程序获取手机号 php 解密

    首先是把这个文件夹放到\ThinkPHP\Library\Org里面 //zll 根据加密字符串和session_key和iv获取手机号 /** * [getphone description] * ...

  6. [转载]Ocelot简易教程(五)之集成IdentityServer认证以及授权

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9807125.html 最近比较懒,所以隔了N天才来继续更新第五篇Ocelot简易教程,本篇教程会先简单介 ...

  7. Linux与Windows 10用grub引导教程

    前言 去年暑假的时候,写了一篇如何装 Linux 和 Windows 10 双系统的文章发在了简书上,我写这篇文章的原因是当初装双系统确实是折腾了许久,网上也找不到一篇详尽的教程.由于去年对于写教程还 ...

  8. android SQLite 使用实例

    Android作为眼下主流的移动操作系统,全然符合SQLite占用资源少的优势,故在Android平台上,集成了一个嵌入式关系型数据库-SQLite.假设想要开发 Android 应用程序,须要在 A ...

  9. 前端js实现打印excel表格

    产品原型: 图片.png 功能需求:点击导出考勤表格按钮,会自动下载成Excel格式 图片.png 图片.png jsp页面代码: <div class="tools"> ...

  10. 【hdu 1067】Gap

    Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission( ...