函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当他具体执行的时候,将根据传递的实际参数决定其功能(运行期间的多态,动态多态)。C++提供两种模板机制:类模板和函数模板。
注意这里T类型必须在使用模板的时候定义,而且可以有多个T类型,这里的typename可以改为class,意味一个通用类,两种写法相同。
template//函数或类的声明或定义
如果在模板类中想要声明一个模板方法,可以直接使用定义类时定义的typename T。
普通函数与函数模板的区别
- 普通函数调用时可以发生自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,可以发服务器托管网生隐式类型转换
模板函数的特点
- 模板函数也可以被重载
- C++编译器在调用的时候会优先考虑普通函数
- 如果函数模板可以产生一个更好的匹配,那么就选择模板(特化)
- 在项目中定义函数模板时,声明和定义必须在同一个文件里。
泛型编程和模板元编程
所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议
元编程侧重点在于「用代码生成代码」,泛型编程侧重点在于「减小代码对特定数据类型的依赖」。而这两个功能在C++中,模板功能可以实现。
模板的全特化和偏特化
模板为什么要特化,因为编译器认为,对于特定的类型,如果你能对某一功能更好的实现,那么就该听你的。
模板分为类模板与函数模板,特化分为全特化与偏特化。全特化就是限定死模板实现的具体类型,偏特化就是如果这个模板有多个类型,那么只限定其中的一部分。
特化并不是完全取代原来的模板,如果传入的参数不满足特化类型的参数的话,还是会调用之前的模板函数
编译器不支持函数模板的偏特化,原因很简单,因为已经有模板函数的重载可以实现这种功能了。
注意在尖括号内规定类型才叫做特化,在参数列表中规定类型叫做重载
template
class C{} //特化
template
void f(int a){} //重载
为什么模板的定义和声明必须在一起
假设有代码段如下
//-----------------text.h---------------//
void f();//声明一个函数
//-----------------test.cpp-----------//
#include "test.h"
void f(){}
//-----------------main.cpp----------//
#include"test.h"
int main(){
f();
}
在这个例子中
编译main.cpp时,编译器不知道f的实现,所以当碰到对它的调用时只是给出一个指示,指示连接器应该为它寻找f的实现体。这也就是说main.obj(可执行文件)中没有关于f的任何一行二进制代码。
编译test.cpp时,编译器找到了f的实现。于是乎f的实现(二进制代码)出现在test.obj里。
连接时,连接器在test.obj中找到f的实现代码(二进制)的地址(通过符号导出表)。然后将main.obj中悬而未决的调用函数f的部分的地址改成f实际的地址。完成。
对于模板函数来说,模板函数的代码并不能直接编译成二进制代码(运行时编译),其中要有一个实例化的过程。
在上述例子中,如果f是一个模板函数且main.cpp中没有调用过,f就得不到实例化,从而main.obj中就没有f的任意一行二进制代码。而当我们调用乐f(1.1),f(1)时,f和f两个函数的二进制代码段就会生成在main.obj中
而实例化要求编译器知道模板的定义
在分离式编译的环境下,编译器编译某一个.cpp文件时并不知道另一个.cpp文件的存在,也不会去查找(当遇到未决符号时它会寄希望于连接器)。这种模式在没有模板的情况下运行良好,但遇到模板时就傻眼了,因为模板仅在需要的时候才会实例化出来,所以,当编译器只看到模板的声明时,它不能实例化该模板,只能创建一个具有外部连接的符号并期待连接器能够将符号的地址决议出来。然而当实现该模板的.cpp文件中没有用到模板的实例时,编译器懒得去实例服务器托管网化,所以,整个工程的.obj中就找不到一行模板实例的二进制代码,于是连接器也黔驴技穷了。
模板的优缺点
优点:
1. 灵活性, 可重用性和可扩展性;
2. 可以大大减少开发时间,模板可以把用同一个算法去适用于不同类型数据,在编译时确定具体的数据类型;
3. 模版模拟多态要比C++类继承实现多态效率要高, 无虚函数, 无继承;
缺点:
1. 易读性比较不好,调试比较困难;
2. 模板的数据类型只能在编译时才能被确定;
3. 所有用基于模板算法的实现必须包含在整个设计的.h头文件中, 当工程比较大的时候, 编译时间较长;
4.如果模板中传入的typename是函数指针类型,那么会导致模板效率很低。并且他会在每次实例化的时候,如果传入的方式不同(lambda表达式,函数指针等方式),都生成一个新的对象。
另外:
up-cast
“upcast”是一个术语,指的是将一个子类的实例转换为它的父类类型的一个过程。这种转换是安全的,因为子类继承了父类的所有属性和方法,所以它保证了父类类型的所有操作在子类实例上都是合法的。
在面向对象编程中,通常有继承层次结构,子类继承父类。当有一个子类对象,并且我们将它赋值给父类类型的引用或变量时,这个操作就是upcasting。由于子类具有父类的所有功能,所以向上转型通常是隐式的和自动的。
成员模板 函数模板 类模板
成员模板
在C++模板编程中,除了可以创建整个类的模板,还可以创建类中单独成员函数的模板,这种成员函数模板称为成员模板(Member templates)。成员模板可以在普通类中定义,也可以在类模板中定义。
当在普通类(非模板类)中定义时,成员模板通常用来定义那些能够处理不同类型参数的成员函数,而不必针对这个类本身使用模板。
普通类中的成员模板示例:
class MyClass {
public:
// 成员模板函数
template
void doSomething(T param) {
// 处理param...
}
};
在这个例子中,虽然 MyClass 不是模板类,它包含了一个模板成员函数(成员模板)doSomething,这个函数可以接受任意类型的参数。
如果成员模板是在类模板中定义的,它会提供更多针对不同类型操作的灵活性。这意味着即使类的实例化类型已经确定,成员模板仍然可以接收和处理不同类型的参数。
类模板中的成员模板示例:
template
class MyTemplateClass {
public:
// 构造函数
MyTemplateClass(T value) : data(value) {}
// 成员模板函数,可以接受与类模板参数不同的类型
template
void doSomething(U param) {
// 处理param和data...
}
private:
T data;
};
// 使用示例
int main() {
MyTemplateClass myInstance(10);
// 调用成员模板函数,使用与类实例化类型不同的类型参数
myInstance.doSomething("Hello world");
}
在这个例子中,即使 MyTemplateClass 被实例化为 int 类型,成员模板函数 doSomething 仍然可以被调用,并处理一个 const char* 类型的字符串。
成员模板在编写泛化的代码时非常有用,它们可以增加类的灵活性,提供处理不同类型数据的能力,无论这些数据是否与类的模板类型参数相同。这对于编写如容器类、算法等泛型编程的库非常重要,比如STL中就广泛使用了成员模板。
函数模板
C++模板编程是一种基于泛型的编程范式,它允许程序员编写与数据类型无关的代码。模板可用于函数模板和类模板。
函数模板 允许我们创建一个函数原型,其中一个或多个参数类型是泛型的。当我们使用不同的数据类型调用该函数时,编译器会为我们自动生成相应类型的函数实例。
例如,一个简单的交换函数模板可能是这样的:
template
void swap(T& a, T& b) {
T temp = a;
a = b;
b = temp;
}
在该例中,typename T 是一个模板参数,代表了将要使用这个函数的任意类型。swap 函数可以用于任何数据类型,例如 int、double 或者自定义的类。
类模板
类模板 工作原理相似,但它们用于创建泛型的数据结构或类。
例如,一个简单的类模板用于创建一个数组容器可能是这样的:
template
class Array {
private:
T* data;
int size;
public:
Array(int size) : size(size) {
data = new T[size];
}
~Array() {
delete[] data;
}
void set(int index, T value) {
if (index >= 0 && index = 0 && index
在上述例子中,我们定义了一个Array模板,它可以存储任何给定类型T的元素数组。
在实际使用中,模板编程可以提高代码复用性和灵活性,但同时也会增加编译器的编译时间,因为需要为不同类型生成不同的实例。此外,模板错误有时可能难以调试,因为它们可能产生冗长且难以理解的错误信息。
理解模板的基本概念对于理解和使用C++的STL(Standard Template Library)至关重要,因为STL广泛使用了模板来实现各种通用、高效的数据结构和算法。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: redis(其它操作、管道)、django中使用redis(通用方案、 第三方模块)、django缓存、celery介绍(celery的快速使用)
1 redis其它操作 2 redis管道 3 django中使用redis 3.1 通用方案 3.2 第三方模块 4 django缓存 5 celery介绍 5.1 celery的快速使用 1 redis其它操作 ”’ delete(*names) exi…