C++中的模板编程
一,函数模板
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++中的模板编程的更多相关文章
- C++ 11可变参数接口设计在模板编程中应用的一点点总结
概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...
- C++模板编程中只特化模板类的一个成员函数
模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多数成员函数的功能可能是一模一样的,特化时我们可能只需要重新实现1.2个成员函数即可.在这种情况下,如果全 ...
- C#中的函数式编程:递归与纯函数(二) 学习ASP.NET Core Razor 编程系列四——Asp.Net Core Razor列表模板页面
C#中的函数式编程:递归与纯函数(二) 在序言中,我们提到函数式编程的两大特征:无副作用.函数是第一公民.现在,我们先来深入第一个特征:无副作用. 无副作用是通过引用透明(Referential ...
- C++模板编程中只特化模板类的一个成员函数(花样特化一个成员函数)
转自:https://www.cnblogs.com/zhoug2020/p/6581477.html 模板编程中如果要特化或偏特化(局部特化)一个类模板,需要特化该类模板的所有成员函数.类模板中大多 ...
- C++之模板编程
当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对象都具有共性. 比如 数值可以增加.减少:字符串也可以增加减少. 它们的动作是相似的, 只是对象的类型不同 ...
- UE4 中的 C++ 编程介绍
https://docs.unrealengine.com/latest/CHN/Programming/Introduction/index.html UE4 中的 C++ 编程介绍 Unreal ...
- c++ 基于Policy 的 模板编程
在没真正接触c++ 模板编程之前.真的没有想到c++ 还能够这么用.最大的感触是:太灵活了,太强大了. 最初接触模板威力还是在Delta3d中,感觉里面的模板使用实在是灵活与方便,特别是dtAI中使 ...
- C++中函数模板的概念和意义
1,对泛型编程进行学习,泛型编程是实际工程开发中必用的技术,大型公司的通用 库都是采用泛型编程的技术完成的,C++ 中支持泛型编程技术,C++ 中的函数 模板和类模板就是 C++ 中泛型编程技术,本 ...
- C++中函数模板的深入理解
1,函数模板深入理解: 1,编译器从函数模板通过具体类型产生不同的函数: 1,模板就是模子,通过这个模子可以产生很多的实物: 2,函数模板就是编译器用来产生具体函数的模子: 2,编译器会对函数模板进行 ...
随机推荐
- express 学习笔记(一)路由
先导入express: var express = require('express'); var app = express(); 1.路由方法: get, post, put, head, del ...
- 自定义npm包——typeScript版本
前言 这篇文章是在我之前的文章 [自定义npm包的创建.发布.更新和撤销] 的基础上做的扩展,主要是针对如何创建以及发布一个typeScript语言的npm包. 大纲 1.创建关于typeScript ...
- element ui源码解析 -- button篇
要看源码就得从最简单的开始,button够简单的了,就从他开始吧. 安装依赖后源码目录在:node_modules/element-ui/packages中,可以看到这里的文件夹命名是不是很熟悉,就是 ...
- LA 3135 - Argus
看题:传送门 大意就是让你编写一个称为argus的系统,这个系统支持一个register的命令: Register Q_num Period 该命令注册了一个触发器,它每Period秒就会残生一个编 ...
- OC学习篇之---Foundation框架中的NSDictionary类以及NSMutableDictionary类
今天来看一下Foundation框架中的NSDictionary类,NSMutableDictionary类,这个和Java中的Map类很想,OC中叫字典,Java中叫Map,还有字典是无序的,这个和 ...
- [WASM] Write to WebAssembly Memory from JavaScript
We write a function that converts a string to lowercase in WebAssembly, demonstrating how to set the ...
- Nginx系列(二)--模块化
高度模块化的设计设Nginx架构的基础. 在Nginx中,除了少量的核心代码,其它一切皆为模块.模块化设计具有下面特点: 1.高度抽象的模块接口 2.灵活性 3.配置模块的设计使Nginx提供了高可配 ...
- JScript使用正则表达式的经验
作者:朱金灿 来源:http://blog.csdn.net/clever101 在JScript使用正则表达式时有不少元字符在试图对其进行匹配时需要进行特殊的处理.要匹配这些特殊字符,必须首先将这些 ...
- python类继承时构造函数的运行问题
假设子类定义了自己的__init__构造方法函数.当子类的实例对象被创建时,子类仅仅会运行自己的__init__方法函数.假设子类没有定义自己的构造方法函数.会沿着搜索树找到父类的构造方法函数去运行父 ...
- P2P网络借贷系统-核心功能-用户投标-业务讲解
用户投标是P2P网络借贷系统的核心功能,相对比较复杂,为了更好地梳理业务和技术实现思路,特地详细总结分析下. 输入:用户id-uid,标的id-lid,投标金额-amount 1.根据lid,获得贷款 ...