内蒙古网站建设信息,做二手车网站需要什么,去掉 wordpress.org,江苏专业做网站的公司哪家好作者主页 #x1f4da;lovewold少个r博客主页 ⚠️本文重点#xff1a;c模板初阶知识点讲解 #x1f449;【C-C入门系列专栏】#xff1a;博客文章专栏传送门 #x1f604;每日一言#xff1a;花有重开日#xff0c;人无再少年 目录
前言
泛型编程
函数模板
函数模… 作者主页 lovewold少个r博客主页 ⚠️本文重点c模板初阶知识点讲解 【C-C入门系列专栏】博客文章专栏传送门 每日一言花有重开日人无再少年 目录
前言
泛型编程
函数模板
函数模板概念
函数模板格式
函数模板的原理
函数模板的实例化
模板参数的匹配原则
类模板
类模板的定义格式
类模板的实例化
总结 前言 C是一门面向对象的语言很多情况下我们不需要在编写程序时候去过多的考虑底层。而在前面我们学习C的输入输出好像就是这样子编译器会自动帮我们做很多的事情而不需要自己去传递输入输出的变量类型等因素。这种方式肯定对于编写程序的人来讲是轻松的。世界上的各种科技的进步其实都离不开人对于懒惰的追求对于方便的执着而今天我要讲解的模板好像就算是一种特殊的产物。 首先我们先写一个比较简单的程序来细致的探究一下我们为何需要模板。这里我们写了一个用于整形变量交换的函数交换函数无论是在什么排序亦或者一些计算的时候都是常用函数。 void swap(int x, int y)
{int temp x;x y;y temp;
}
int main()
{int a 10;int b 5;cout a a b b endl;swap(a, b);cout swap~ endl;cout a a b b endl;return 0;
} 问题来了我们这里需要特别强调这里是用于整形类型的交换函数因此这对于其他类型变量并不合适。那么我们如何去实现长整形短整形浮点型字符型······。函数重载 C提供了函数重载的方式对于一些传参会直接以其传递参数而决定对应的函数。 但是缺陷也很明显我们的函数仅仅是类型不同那么多类型我们都需要去重载么。亦或者我们先创建我们需要的类型等到新类型出现的时候用户再自己去增加对应的函数重载么。 另一个关键点是我们这里仅仅只是交换函数比较简单而对于一份各种函数相互嵌套的代码一份代码出错其他重载函数全得改代码的可维护性比较低。
泛型编程 我们再看先前的代码会发现仅仅只是类型的不同罢了我们可不可以提供一种方式和cout以及cin一样把类型识别的任务交给编译器去完成自己只需要给他传递参数变量即可。也就是说我们只需要提供一份代码作为模具编译器可以根据不同的类型利用这个模具生成相应的代码。
void swap(int x, int y)
{int temp x;x y;y temp;
}
void swap(double x, double y)
{double temp x;x y;y temp;
}
void swap(char x, char y)
{char temp x;x y;y temp;
}
int main()
{int a 10;int b 5;cout a a b b endl;swap(a, b);cout swap~ endl;cout a a b b endl;return 0;
} 无论是活字印刷术还是现在的模具浇筑技术其根本的目的就是维持其功能一致即可你可以注入不同的材料以改变其最后成品的效果但本质上实现的功能是一样的外形是一致的。 之所以cv工程师能有独特的cv大法也是因为前人拥有特定的已经可以使用的板子而只需要去改吧改吧然后切合自己的工程内容即可实现一个全新的项目成果。这也就是一种代码复用的常规手段而已。 话不多说接下来直入正题。我们先谈一谈何为泛型编程。 泛型编程是一种编程范式其目标是编写与特定数据类型无关的通用代码以便更广泛地重用代码。泛型编程使得程序员可以编写与数据类型无关的算法和数据结构从而提高代码的灵活性、可重用性和可维护性。 具体而言泛型编程通过使用参数化类型parameterized types来实现。参数化类型是一种允许在代码中使用未指定具体类型的抽象类型。这样可以编写算法和数据结构而不必在编写时指定具体的数据类型。在需要使用这些算法和数据结构的地方可以通过提供具体的类型来实现参数的具体化。 在C中泛型编程主要通过模板来实现。模板允许程序员编写与数据类型无关的代码可以用于不同的数据类型。这使得在不同的上下文中重用代码成为可能。例如可以编写通用的排序算法、容器类、以及其他算法和数据结构而不必为每种数据类型都编写一套特定的代码。而模板就是泛型编程的基础。 函数模板
函数模板概念 函数模板是C中用于创建通用函数的一种机制允许程序员编写与特定数据类型无关的函数代码。函数模板通过使用参数化类型来实现使得可以在编写代码时使用未指定具体类型的抽象类型。这样函数模板可以适用于多种数据类型提高了代码的灵活性和重用性。
函数模板格式 templatetypename T
void Swap(T x,T y)
{T temp x;x y;y temp;
}template T 表示模板参数T是一个占位符代表任意数据类型。在函数模板中可以使用T作为函数的参数类型、返回类型以及在函数体中进行通用的操作。 注意typename是用来定义模板关键字也可以使用class不能使用struct代替class 函数模板的原理 人类从农业时期到工业时期很多重复机械的工作直接交给了机器去完成极大的解放的生产力。机器生产淘汰了很多手工创作的东西其本质上就是把这些工作交给了机器去完成。 函数模板本身并不是一个函数而是像类一样作为一个蓝图是编译器用使用方式产生具体类型函数的一个模具。 在编译器编译阶段对于模板函数的使用编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如int类型使用函数模板时编译器根据传递的实参类型的推演将T确定为int类型然后再专门产生一份处理int类型的代码对于double类型还是字符类型皆是这样 函数模板的实例化
用不同类型的参数使用函数模板的时候称之为函数模板的实例化。模板参数实例化分为隐式实例化和显式实例化。
隐式实例化让编译器根据传递的实参类型推演模板参数的实际类型。
template class T
T Add(const T left, const T right)
{return left right;
}int main()
{int a1 10;int a2 5;Add(a1, a2);double b1 10.0;double b2 5.0;Add(b1, b2);return 0;
} 而当调用的时候将不同类型混合传参是不被允许的因为在编译期间编译器需要推演对于a1可以推演为intb1可以推演为double但是模板参数列表中只有一个T编译器无法确定T被换为int还是double而报错。在模板中编译器一般不会去做类型转换否则出错了编译器就会承担不小的后果。 因此对于这种问题我们通常有两种方式进行解决用户自己进行强制类型转换或者使用显示实例化 显示实例化在函数名的后面指定模板参数的实际类型
int main()
{int a1 10;int a2 5;Add(a1, a2);double b1 10.0;double b2 5.0;Add(b1, b2);Addint(a1, b1);//显示实例化return 0;
}
模板参数的匹配原则 一个非模板函数和模板函数可以同时存在而且该模板函数还可以实例化为这个非模板函数。这种实例化为非模板函数指在参数传递上可能维持一样但是依据优先匹配的原则在调用函数的时候可以做一些特殊处理。这里我们通过不同函数之间打印信息而进行调用优先级的查看。 //专门处理整形类型加法函数
int Add(int left, int right)
{cout 非模板函数 endl;return left right;
}
//通用加法模板
templateclass T
T Add(T left, T right)
{cout 模板函数 endl;return left right;
}
void test()
{Add(1,2);//与非模板函数优先匹配Add(1.0, 2.0);//模板函数Addint(1, 2);//调用特定版本的Add版本走模板函数
}
int main()
{test();return 0;
} 对于非模板函数与同名函数模板如果有其他条件相同在调用的时候会优先去调用非函数模板而不会从该函数模板中生成实例化函数如果一个函数可以产生一个具有更好匹配的函数那么选择模板。
int Add(int left, int right)
{cout 非模板函数 endl;return left right;
}
//通用加法模板
templateclass T1 , class T2
T1 Add(T1 left, T2 right)
{cout 模板函数 endl;return left right;
}
void test()
{Add(1, 2);//与非模板函数优先匹配Add(1, 2.0);//具备更加匹配的版本而不需要类型转换编译器优先生成更加匹配的Add函数版本
}
int main()
{test();return 0;
} 模板函数不能进行自动类型转换帮你推演就够忙了类型转换发生错误你还得骂他自然就不会帮你做这件没意义的事情。但是普通函数可以进行自动类型转换
类模板
类模板的定义格式
templateclass T1, class T2,class T3//参数列表可以定义多个模板变量
class 类模板名
{//类成员定义
}; 我们前面学习顺序表提到过一点使用typedef对类型名进行重命名。C语言中的类型重命名是指通过使用typedef关键字来为已有的类型创建一个新的别名。这样可以简化代码提高可读性并且方便批量修改具体类型便于维护代码。但是当我们学习了类模板之后我们发现我们并不需要这样做而是使用类模板。这里我们简要的构造一个动态顺序表的类模板来体会。
templateclass T
class Vector
{
public:Vector(size_t capacity 10): _pData(new T[capacity]), _size(0), _capacity(capacity){}~Vector();// 其他成员函数在这里...size_t Size() { return _size; };T operator[](size_t pos){assert(pos _size);return _pData[pos];}private:T* _pData;size_t _size;size_t _capacity;
};// 类模板函数定义可以放在类定义外面。
templateclass T
VectorT::~Vector()
{if (_pData){delete[] _pData;}_size _capacity 0;
}
类模板的实例化 类模板的实例化与函数模板实例化不同类模板实例化需要在类模板的名字前面跟,然后需要讲实例化的类型放在中即可就像必须显式的实例化。类模板名字不是真正的类而实例化的结果才是真正的类蓝图和用蓝图进行建筑的关系。实例化时编译器会生成针对具体数据类型的类定义从而使得类模板变得具体化可以像普通类一样使用。 Vector类名Vectorint才是类型Vectorint s1;Vectordouble s2; 总结 泛型编程是一种编程范式其目标是编写可重用、通用的代码以便能够适应多种数据类型而无需针对每种类型重复编写相似的代码。在C中泛型编程主要通过函数模板和类模板来实现。其优势如下 提高代码的重用性和可维护性。 允许在不同数据类型上进行抽象减少代码冗余。 函数模板Function Templates 概念函数模板是一种定义通用函数的方式其中函数的参数或返回类型可以是通用的类型参数。 语法 template class T //typename也可以
T Add(T a, T b)
{return a b;
} 实例化通过指定具体的数据类型编译器会生成对应类型的函数定义。 实例化用法 int r_int Add(3, 4); // 实例化为 Addint(3, 4)
double r_double Add(3.14, 2.5);// 实例化为 Adddouble(3.14, 2.5) 类模板Class Templates 概念类模板是一种定义通用类的方式其中类的成员或行为可以依赖于通用的类型参数。 语法 template class T class MyClass {public:MyClass(T value) : data(value) {}void play() { /* ... */ }private:T data;}; 实例化通过指定具体的数据类型编译器会生成对应类型的类定义。 使用 MyClassint intObject(42);MyClassdouble doubleObject(3.14); 作者水平有限如有错误欢迎指正