Sequential List
Coding
//Basic Data Structure Day1 Sequential List
//顺序表
#include <iostream>
using namespace std;
#define eleType int
struct SequentialList {//定义顺序表结构
eleType* elements;
int size; //顺序表当前的大小,元素的个数
int capacity; //顺序表的容量,就是数组的大小
};
void intializeList(SequentialList* list, int capacity) {//初始化顺序表
list->elements = new eleType[capacity];
list->size = 0;
list->capacity = capacity;
}
void destroyList(SequentialList* list) {//删除整个顺序表
delete[] list->elements;
}
int main() {
return 0;
}
“C++ 泛型编程” 的标准英文表述是 C++ Generic Programming。
补充说明:
- 核心概念解析
- Generic Programming(泛型编程):是一种编程范式,核心思想是 “编写与具体数据类型无关的代码,在使用时再指定具体类型”,从而实现代码的复用性、灵活性和类型安全性。
- 在 C++ 中,泛型编程的主要实现手段是 Templates(模板),包括函数模板(Function Templates)和类模板(Class Templates),例如 std::vector、std::sort 等标准库组件均基于模板实现,支持不同数据类型(如 int、std::string)的通用操作。
- 常见搭配与场景
- 描述技术特性:Generic Programming in C++(C++ 中的泛型编程)、C++ Generic Programming Techniques(C++ 泛型编程技巧)。
- 关联组件:C++ Template-based Generic Programming(基于 C++ 模板的泛型编程)、Generic Data Structures in C++(C++ 中的泛型数据结构)。
- 与相关概念的区分
有时容易与 “泛型” 混淆的是 “多态(Polymorphism)”,但二者本质不同:- 泛型编程(Generic Programming):编译期确定类型,通过模板生成特定类型的代码,属于 “静态多态”;
- 面向对象的多态(OOP Polymorphism):运行期确定类型,通过虚函数实现,属于 “动态多态”。
例如,以下是 C++ 泛型编程(基于模板)的简单示例:
cpp
// 函数模板:通用的加法函数,支持任意可相加的类型
template <typename T>
T add(T a, T b) {
return a + b;
}
int main() {
int num1 = 3, num2 = 5;
double num3 = 2.1, num4 = 3.5;
std::cout << add(num1, num2) << std::endl; // 编译期生成 int 版本的 add
std::cout << add(num3, num4) << std::endl; // 编译期生成 double 版本的 add
return 0;
}
//C++ Generic Programming – Chapter 2 – Function Template – 2.1 Function Template Definition
//C++ 泛型变成 – 二、函数模板 2.1 函数模板定义
#include <iostream>
using namespace std;
//函数模板
//就是建立一个通用的函数
//这个通用的函数 它的返回值和参数列表的类型 在定义的时候可以不指定 等到函数调用时再去指定
//相当于把形参类型和返回值的类型给它抽象出来 定义的时候不知道它的类型 只有在调用的时候才真正确定数据类型
/*
template <typename T>
函数的定义
T是通用类型
*/
int addInt(int a, int b) { //整型
int c = a + b;
return c;
}
double addDouble(double a, double b) {//浮点型
double c = a + b;
return c;
}
//这两个函数 除了类型不一样 其它都一样 框架一样
//小学提取公因式
//T是虚拟类型
template<typename T>//在前面加上函数模板定义 T变成自己定义的类型 编译就不会报错了
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
int c = addInt(a, b);
cout << c << endl;
double aa = 1.1, bb = 1.91;
double cc = addDouble(aa, bb);
cout << cc << endl;
return 0;
}
“自动类型推导” 的英文是 Automatic Type Deduction。
补充说明:
- 核心含义:指编程语言中由编译器或解释器根据变量的初始化值、表达式结果等信息,自动推断出变量或表达式数据类型的机制,无需开发者显式声明类型。
- 常见应用场景:在 C++(如 auto 关键字)、Python(动态类型语言,天生支持类型推导)、Java(Java 10+ 的 var 关键字)、Go 等语言中广泛使用。
- 示例(C++):auto num = 10;(编译器自动推导 num 为 int 类型)
- 示例(Python):name = “Alice”(解释器自动推导 name 为字符串类型)
- 相关术语:
- 若特指某类语言特性,可能会搭配具体关键字表述,如 auto Type Deduction(C++ 中基于 auto 的推导)、var Type Inference(Java/JavaScript 中基于 var 的推导,“Inference” 与 “Deduction” 在此语境下可通用,前者更侧重 “推断逻辑”,后者更侧重 “推导过程”)。
//C++ Generic Programming – Chapter 2 – 2.2.1 Function Template Calling – Automatic Type Deduction
//C++ 泛型编程 2.2.1 函数模板调用 – 自动类型推导
#include <iostream>
using namespace std;
//调用函数模板的方法有两种
//1.自动类型推导
//2.显式指定类型
//函数模板
//就是建立一个通用的函数
//这个通用的函数 它的返回值和参数列表的类型 在定义的时候可以不指定 等到函数调用时再去指定
//相当于把形参类型和返回值的类型给它抽象出来 定义的时候不知道它的类型 只有在调用的时候才真正确定数据类型
/*
template <typename T>
函数的定义
T是通用类型
*/
int addInt(int a, int b) { //整型
int c = a + b;
return c;
}
double addDouble(double a, double b) {//浮点型
double c = a + b;
return c;
}
//这两个函数 除了类型不一样 其它都一样 框架一样
//小学提取公因式
//T是虚拟类型
template<typename T>//在前面加上函数模板定义 T变成自己定义的类型 编译就不会报错了
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
int c = addInt(a, b);
cout << c << endl;
double aa = 1.1, bb = 1.91;
double cc = addDouble(aa, bb);
cout << cc << endl;
//自动类型推导
// 自动类型推导 编译器根据a和b的数据类型 去自己推导 并且找到合适的函数模板进行调用 只要没有不确定的数据类型就可以正常编译输出
// 好处就是把addInt和addDouble的函数变成一个函数去定义,这样就可以减少冗余的代码
//调用一个add,把a和b传进来
c=add(a, b);
cout << c << endl;
cc = add(aa, bb);
cout << cc << endl;
return 0;
}
//C++ Generic Programming – Chapter 2 – 2.2.2 Function Template Calling – Explicitly Specify the Type
//C++ 泛型编程 2.2.2 函数模板调用 – 显式指定类型
#include <iostream>
using namespace std;
//调用函数模板的方法有两种
//1.自动类型推导
//2.显式指定类型
//函数模板
//就是建立一个通用的函数
//这个通用的函数 它的返回值和参数列表的类型 在定义的时候可以不指定 等到函数调用时再去指定
//相当于把形参类型和返回值的类型给它抽象出来 定义的时候不知道它的类型 只有在调用的时候才真正确定数据类型
/*
template <typename T>
函数的定义
T是通用类型
*/
int addInt(int a, int b) { //整型
int c = a + b;
return c;
}
double addDouble(double a, double b) {//浮点型
double c = a + b;
return c;
}
//这两个函数 除了类型不一样 其它都一样 框架一样
//小学提取公因式
//T是虚拟类型
template<typename T>//在前面加上函数模板定义 T变成自己定义的类型 编译就不会报错了
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
int c = addInt(a, b);
cout << c << endl;
double aa = 1.1, bb = 1.91;
double cc = addDouble(aa, bb);
cout << cc << endl;
//自动类型推导
// 自动类型推导 编译器根据a和b的数据类型 去自己推导 并且找到合适的函数模板进行调用 只要没有不确定的数据类型就可以正常编译输出
// 好处就是把addInt和addDouble的函数变成一个函数去定义,这样就可以减少冗余的代码
//调用一个add,把a和b传进来
/*
c = add(a, b);
cout << c << endl;
cc = add(aa, bb);
cout << cc << endl;
*/
//显式指定类型
//显式指定类型就是在调用的时候直接告诉编译器 我这里的T是个什么类型 不需要编译器进行自动推导
c=add<int>(a, b); //这个<int>实际上就是程序员告诉编译器 接下来我要调用的这个函数 指定了T的这个类型是尖括号里面的这个int
cout << c << endl;
cc = add<double>(aa, bb);//我只要指定了这个类型 我这个add函数 只需要实现一个
cout << cc << endl;
//甚至以后出现了char类型
add<char>(‘a’, ‘b’);
return 0;
}
//C++ Generic Programming – Chapter 2 – 2.3.1 The Differences between Regular Functions – Regular Functions has Implicit Type Conversion
//C++泛型编程 第二章-函数模板 2.3.1 与普通函数区别 – 普通函数有隐式类型转换
#include <iostream>
using namespace std;
//对于普通函数 在实参变成形参的过程中 变量的类型实际上有可能产生隐式转换
int addInt(int a, int b) { //整型
int c = a + b;
return c;
}
double addDouble(double a, double b) {//浮点型
double c = a + b;
return c;
}
template<typename T>//在前面加上函数模板定义 T变成自己定义的类型 编译就不会报错了
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
//虽然这两个是整型变量 但是我依然可以调用addDouble这个函数 并且把a和b传进来 赋值给一个变量c
double c = addDouble(a, b);
cout << c << endl;
//正常运行 因为整型 a 作为传参的时候 在传的过程中强制转换成这个double 类型
//本来a和b都是整型 在传的过程中强制转换成这个double 类型
//普通函数在调用的时候 如果实参的参数类型和形参的参数类型不匹配 就可能发生隐式类型转换
return 0;
}
是的,在许多编程语言中(如 JavaScript、C++ 等),当函数调用时实参类型与形参类型不匹配时,会发生隐式类型转换(也称为自动类型转换)。
这种转换由编译器或解释器自动完成,目的是尝试让不匹配的类型能够兼容。
以 JavaScript 为例:
javascript
function add(a, b) {
return a + b;
}
console.log(add(5, “10”)); // 输出 “510”,数字5被转换为字符串”5″,然后进行字符串拼接
console.log(add(“5”, 10)); // 输出 “510”,数字10被转换为字符串”10″
console.log(add(true, 5)); // 输出 6,布尔值true被转换为数字1
console.log(add(null, 5)); // 输出 5,null被转换为数字0
在 C++ 中也有类似的隐式转换:
cpp
#include <iostream>
using namespace std;
void printNumber(int num) {
cout << “Number: ” << num << endl;
}
int main() {
printNumber(‘A’); // 字符’A’被转换为ASCII码值65
printNumber(3.14); // 浮点数3.14被转换为整数3
return 0;
}
隐式类型转换虽然方便,但也可能导致意外的结果,尤其是在 JavaScript 等弱类型语言中。因此,在编写代码时,最好显式地进行类型转换,以确保代码的可读性和正确性。
//C++ Generic Programming – Chapter 2 – Function Templates’ differences between regular functions 2.3.2 Function Templates Automatic Type Deduction without Implicit Type Conversion
//C++ 泛型编程 – 第二章 – 函数模板 – 函数模板与普通函数的区别 2.3.2 函数模板自动类型推导无隐式类型转换
#include <iostream>
using namespace std;
//在函数模板进行自动类型推导时 无法进行隐式类型转换
int addInt(int a, int b) { //整型
int c = a + b;
return c;
}
double addDouble(double a, double b) {//浮点型
double c = a + b;
return c;
}
template<typename T>//在前面加上函数模板定义 T变成自己定义的类型 编译就不会报错了
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
int c = add(a, b);//这是自动类型推导
cout << c << endl;
double d = 2.5;
//int e = add(a, d);//这里出问题了 说没有与参数列表匹配的函数模板
// 错误!函数模板自动类型推导 无法进行 隐式类型转换
//a参数传入时 由于a是int类型 所以它把形参类型T推导成了 int
//当d参数传入时 因为它是double类型 所以它把形参类型T推导成double类型
//然后这时候就冲突了 因为T不可能又是int又是double
//函数模板进行自动类型推导时 无法进行隐式类型转换
return 0;
}
//C++ Generic Programming – Chapter 2 – Function Templates’ differences between regular functions-2.3.3-Explicitly Specifying the Type with Implicit Type Conversion
//C++ 泛型编程 – 第二章 – 函数模板 – 函数模板与普通函数的区别 2.3.3 函数模板显式指定类型有隐式类型转换
#include <iostream>
using namespace std;
//在函数模板进行自动类型推导时 无法进行隐式类型转换
int addInt(int a, int b) { //整型
int c = a + b;
return c;
}
double addDouble(double a, double b) {//浮点型
double c = a + b;
return c;
}
template<typename T>//在前面加上函数模板定义 T变成自己定义的类型 编译就不会报错了
T add(T a, T b) {
T c = a + b;
return c;
}
int main() {
int a = 1, b = 2;
double d = 2.1;
//int e = add(a, d);//这里出问题了 说没有与参数列表匹配的函数模板
// 错误!函数模板自动类型推导 无法进行 隐式类型转换
//a参数传入时 由于a是int类型 所以它把形参类型T推导成了 int
//当d参数传入时 因为它是double类型 所以它把形参类型T推导成double类型
//然后这时候就冲突了 因为T不可能又是int又是double
//函数模板进行自动类型推导时 无法进行隐式类型转换
int c = add<int>(a, d);//这样没问题 显式指定类型相当于这个T已经变成 int
//T变成int之后 就算我这个是double 它也能自己进行隐式类型转换
// 函数相当于明确地告诉编译器 请把我这个T推导成int
//这里已经变成普通函数 那就沿用我们之前普通函数的规则:当传入的数据是什么类型不重要 它会在传参的过程中进行隐式的类型转换
//double c = add<double>(a, d);//也可以写 因为无论它转成什么类型 当我传一个类型进来 他都能变成隐式类型转换 根据自己的需要选择合适的数据类型就可以了
//函数模板的 【显式指定类型】 调用时的 【隐式类型转换】
cout << c << endl;
return 0;
}