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,编译器会对函数模板进行 ...
随机推荐
- 《你不知道的JavaScript(上)》笔记——let和const
笔记摘自:<你不知道的JavaScript(上)>第3章 函数作用域和块作用域 let 1.let 关键字可以将变量绑定到所在的任意作用域中 2.let 为其声明的变量隐式地劫持了所在的块 ...
- (转)ipv4的网段表示方法
简单一点举例说明:ip段:10.0.0.1-10.0.0.255 的表示方法:10.0.0.0/24ip段:10.0.0.1-10.0.255.255 的表示方法: ...
- word vba 1 页面视图
- occcont.cpp 925
将InitInstance()中调用的 InitATL() 替换为 AfxOleInit()即可.
- Spring中@Async用法详解及简单实例
Spring中@Async用法 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类 ...
- div宽度设置width:100%后再设置padding或margin超出父元素的解决办法
div宽度设置width:100%后再设置padding或margin超出父元素的解决办法 一.总结 一句话总结:直接加上box-sizing:border-box;即可解决上述问题. 1.box-s ...
- Android自定义组件系列【10】——随ViewPager滑动的导航条
昨天在用到ViewPager实现滑动导航的时候发现微信的导航条效果是跟随ViewPager的滑动而动的,刚开始想了一下,感觉可以使用动画实现,但是这个滑动是随手指时时变化的,貌似不可行,后来再网上搜了 ...
- 数据类型总结——Array(数组类型)
相关文章 简书原文:https://www.jianshu.com/p/1e4425383a65 数据类型总结——概述:https://www.cnblogs.com/shcrk/p/9266015. ...
- inflate, findViewById与setContentView的区别与联系 分类: H1_ANDROID 2014-04-18 22:54 1119人阅读 评论(0) 收藏
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentV ...
- VS2008的C++TR1库已经支持正则表达式
作者:朱金灿 来源:http://blog.csdn.net/clever101 发现VS2008的C++ TR1库已经支持正则表达式了(注意装了VS 2008sp1采用TR1库的).下面简单做个测试 ...