当前位置: 首页 > news >正文

C++提高编程——模板

本专栏记录C++学习过程包括C++基础以及数据结构和算法,其中第一部分计划时间一个月,主要跟着黑马视频教程,学习路线如下,不定时更新,欢迎关注
当前章节处于:
---------第1阶段-C++基础入门
---------第2阶段实战-通讯录管理系统,
---------第3阶段-C++核心编程,
---------第4阶段实战-基于多态的企业职工系统
=====>第5阶段-C++提高编程
---------第6阶段实战-基于STL泛化编程的演讲比赛
---------第7阶段-C++实战项目机房预约管理系统

文章目录

  • 一、概念
  • 二、函数模板
    • 2.1 基本语法
    • 2.2 注意事项
    • 2.3 普通函数和模板函数的区别
    • 2.4 普通函数和函数模板调用规则
    • 2.5 模板的局限性
  • 三、类模板
    • 3.1 基本语法
    • 3.2 类模板中成员函数创建时机
    • 3.3 类模板对象做函数参数
    • 3.4 类模板与继承
    • 3.5 类模板成员函数类外实现
    • 3.6 类模板分文件编写
    • 3.7 类模板和友元

一、概念

模板就是建立通用的模具,大大提高复用性。模板不可以直接使用,只是一个框架,并且模板的通用并不是万能的。使用模板的目的是提高复用性,将类型参数化。

二、函数模板

2.1 基本语法

template
函数声明或定义

  • template:声明创建模板
  • typename:表明其后面的符号是一种数据类型,可以用class代替
  • T:通用的数据类型,名称可以替换,通常为大写字母,可以定义多个
#include <iostream>
using namespace std;// 定义一个交换的函数模板
template <typename T>
void Myswap(T& a, T& b) {T temp = a;a = b;b = temp;
}void test() {int a = 10;int b = 20;char c = 'c';char d = 'd';// 1. 自动推导型Myswap(a, b);cout << "a=" << a << endl;cout << "b=" << b << endl;// 2. 显示推导型Myswap<char>(c, d);cout << "c=" << c << endl;cout << "d=" << d << endl;}int main() {test();system("pause");return 0;}
a=20
b=10
c=d
d=c
请按任意键继续. . .

2.2 注意事项

  1. 自动类型推导,必须推导出一致的数据类型,才可以使用
  2. 模板必须要确定出T的数据类型,才可以使用
    第一个好理解,比如上面的Myswap,如果传入的两个实参类型不一致时,则会导致推导出来的T的类型不一致,则无法使用。下面对于第二点进行代码讲解:
#include <iostream>
using namespace std;// 定义模板
template <class T>
void func() {cout << "调用函数模板" << endl;
}void test() {// func(); // 错误func<int>(); // 正确
}int main() {test();system("pause");return 0;}
调用函数模板
请按任意键继续. . .

实战案例

  • 利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
  • 排序规则从大到小,排序算法为选择排序
  • 分别利用char数组和int数组进行排序
#include <iostream>
using namespace std;// 排序函数模板
template<class T>
void func(T arr[],int length) {// 选择排序for (int i = 0; i < length; i++) {int max = i; // 认为当前的是最大值for (int j = i+1; j < length; j++) {if (arr[max] < arr[j]) {max = j;}}// 调换两个值T temp = arr[i];arr[i] = arr[max];arr[max] = temp;}
}// 打印函数模板
template <class T>
void printArr(T arr[],int length) {for (int i = 0; i < length; i++) {cout << arr[i] << " ";}cout << endl;
}// 测试整型
void test01() {int arr[10] = { 1,4,3,2,6,7,5,9,8,0 };func(arr, 10);printArr(arr, 10);
}
void test02() {char arr[] = "acbdfeg";int length = sizeof(arr) / sizeof(arr[0]);func(arr,length);printArr(arr, length);
}
int main() {test01();test02();system("pause");return 0;}
9 8 7 6 5 4 3 2 1 0
g f e d c b a
请按任意键继续. . .

2.3 普通函数和模板函数的区别

  • 普通函数调用时可以发生自动类型转化(隐式类型转化)
  • 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
  • 如果利用显示指定类型的方式,可以发生隐式类型转化
#include <iostream>
using namespace std;// 定义一个函数模板
template<class T>
T func1(T a, T b) {cout << "调用的是函数模板!" << endl;return a + b;
}// 定义一个普通函数
int func2(int a,int b) {cout << "调用的是普通函数!" << endl;return a + b;
}// 测试案例
void test() {int a = 10;int b = 20;char c = 'c';cout << func1(a, b) << endl;cout << func2(a, c) << endl;//cout << func1(a, c) << endl;// 报错cout << func1<int>(a, c) << endl;// 不报错
}
int main() {test();system("pause");return 0;}
调用的是函数模板!
30
调用的是普通函数!
109
调用的是函数模板!
109
请按任意键继续. . .

2.4 普通函数和函数模板调用规则

  1. 如果函数模板和普通函数都可以实现,优先调用普通函数
  2. 可以通过空模板参数列表来强制调用函数模板
  3. 函数模板也可以发生重载
  4. 如果函数模板可以更好的匹配,优先调用函数模板

下面通过具体代码进行逐个讲解

#include <iostream>
using namespace std;
// 定义普通函数
void MyPrint(int a,int b) {cout << "调用的是普通函数" << endl;
}// 定义模板函数
template<class T>
void MyPrint(T a, T b) {cout << "调用的是模板函数" << endl;
}
// 重载模板函数
template<typename T>
void MyPrint(T a, T b, T c)
{cout << "调用重载的模板函数" << endl;
}int main() {// 1. 如果函数模板和普通函数都可以实现,优先调用普通函数int a = 10; int b = 20;MyPrint(a, b);// 2.可以通过空模板参数列表来强制调用函数模板MyPrint<>(a, b);// 3.函数模板也可以发生重载MyPrint(a, b, 30);// 4.如果函数模板可以产生更好的匹配,优先调用函数模板char c1 = 'a';char c2 = 'b';MyPrint(c1, c2);system("pause");return 0;}
调用的是普通函数
调用的是模板函数
调用重载的模板函数
调用的是模板函数
请按任意键继续. . .

总结:如果提供了函数模板,最好就不要再提供对应的普通函数,否则容易出现二义性。

2.5 模板的局限性

如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常进行比较运算,C++为了解决这种问题,提供模板的重载,为这些特定类型提供具体化模板。

#include <iostream>
using namespace std;
class Person {
public:Person(string name,int age) {m_Name = name;m_Age = age;}string m_Name;int m_Age;
};
// 普通函数模板
template<class T>
bool myCompare(T& a, T& b) {return a == b;
}
// 具体化 优先于常规模板
template<> bool myCompare(Person& p1, Person& p2) {if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age){return true;}else{return false;}
}void test() {Person p1("Tom", 10);Person p2("Tom", 10);cout << myCompare(p1, p2) << endl;
}
int main() {test();system("pause");return 0;}
1
请按任意键继续. . .

利用具体化的模板,可以解决自定义类型的通用化,学习模板并不是为了写模板,而是再STL中能够运用系统提供的模板。

三、类模板

类似于函数模板,类有也对应的类模板,类模板的作用是建立一个通用类,类中的成员,数据类型可以不具体制定,用一个虚拟的类型来代表,语法为
template<typename T>

  • template — 声明创建模板
  • typename — 表面其后面的符号是一种数据类型,可以用class代替
  • T — 通用的数据类型,名称可以替换,通常为大写字母

3.1 基本语法

#include <iostream>
using namespace std;// 定义一个交换的函数模板
template <typename T>
void Myswap(T& a, T& b) {T temp = a;a = b;b = temp;
}void test() {int a = 10;int b = 20;char c = 'c';char d = 'd';// 1. 自动推导型Myswap(a, b);cout << "a=" << a << endl;cout << "b=" << b << endl;// 2. 显示推导型Myswap<char>(c, d);cout << "c=" << c << endl;cout << "d=" << d << endl;}int main() {test();system("pause");return 0;}
姓名:孙悟空  年龄:999
姓名:猪八戒  年龄:888
请按任意键继续. . .

3.2 类模板中成员函数创建时机

类模板中成员函数和普通类中成员函数创建时机是有区别的:

  • 普通类中的成员函数一开始就可以创建
  • 类模板中的成员函数再调用时才创建
#include <iostream>
using namespace std;
class Person1
{
public:void showPerson1(){cout << "Person1 show" << endl;}
};class Person2
{
public:void showPerson2(){cout << "Person2 show" << endl;}
};
// 定义类模板
template<class T>
class MyClass
{
public:T obj;//类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成void fun1() { obj.showPerson1(); }void fun2() { obj.showPerson2(); }};
void test01()
{MyClass<Person1> m;m.fun1();//m.fun2();//编译会出错,说明函数调用才会去创建成员函数
}
int main() {test01();system("pause");return 0;}
Person1 show
请按任意键继续. . .

3.3 类模板对象做函数参数

类模板实例化出的对象,向函数传参的方式

一共有三种传入方式:

  1. 指定传入的形式:直接显示对象的数据类型,这是用的最多的一种方式
  2. 参数模板化:将对象中的参数变为模板进行传递
  3. 整个类模板化:将这个对象类型,模板化进行传递

下面用代码进行讲解:

#include <iostream>
using namespace std;
// 创建一个类模板
template<class NameType, class AgeType = int> // 默认参数为int
class Person
{
public:Person(NameType name, AgeType age){this->mName = name;this->mAge = age;}void showPerson(){cout << "name: " << this->mName << " age: " << this->mAge << endl;}
public:NameType mName;AgeType mAge;
};
//1、指定传入的类型,最常用的一种方式
void printPerson1(Person<string, int>& p)
{p.showPerson();
}
void test01()
{Person <string, int >p("孙悟空", 100);printPerson1(p);
}//2、参数模板化
template <class T1, class T2>
void printPerson2(Person<T1, T2>& p)
{p.showPerson();cout << "T1的类型为: " << typeid(T1).name() << endl;cout << "T2的类型为: " << typeid(T2).name() << endl;
}
void test02()
{Person <string, int >p("猪八戒", 90);printPerson2(p);
}//3、整个类模板化
template<class T>
void printPerson3(T& p)
{cout << "T的类型为: " << typeid(T).name() << endl;p.showPerson();}
void test03()
{Person <string, int >p("唐僧", 30);printPerson3(p);
}int main() {test01();test02();test03();system("pause");return 0;
}
int main() {system("pause");return 0;}
name: 孙悟空 age: 100
name: 猪八戒 age: 90
T1的类型为: class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
T2的类型为: int
T的类型为: class Person<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int>
name: 唐僧 age: 30
请按任意键继续. . .

3.4 类模板与继承

当类模板碰到继承时,需要注意一下几点:

  • 当子类继承的父类是一个类模板时,子类在声明的时候,要制定出父类中T的类型
  • 如果不指定,编译器无法给子类分配内存
  • 如果想灵活指定出父类中T的类型,子类也需变成类模板
#include <iostream>
// 父类类模板
using namespace std;
template<class T>
class Base
{T m;
};// 子类继承父类
// class Son :public Base {}; // 错误,必须要确定父类中的T
class Son :public Base<int> {};
void test01()
{Son c;// 实例化对象
}
template<class T2>
class Son2 :public Base<T2>
{
public:Son2(){cout << typeid(T2).name() << endl;}
};void test02()
{Son2<char> child1;
}
int main() {test01();test02();system("pause");return 0;}
char
请按任意键继续. . .

3.5 类模板成员函数类外实现

#include <iostream>
using namespace std;template<class NameType, class AgeType = int> // 默认参数为int
class Person
{
public:Person(NameType name, AgeType age);void showPerson();
public:NameType mName;AgeType mAge;
};
// 构造函数 类外实现
template<class NameType, class AgeType>
Person<NameType, AgeType>::Person(NameType name, AgeType age)
{this->mName = name;this->mAge = age;
}
// 成员函数类外实现
template<class NameType, class AgeType>
void Person<NameType, AgeType>::showPerson()
{cout << "name: " << this->mName << " age: " << this->mAge << endl;
}int main() {Person<string, int> p("张三", 13);p.showPerson();system("pause");return 0;}
name: 张三 age: 13
请按任意键继续. . .

3.6 类模板分文件编写

由于类模板中成员函数创建时机是在调用阶段,导致分文件编写时连接不到,有两种解决方案:

  • 直接包含cpp源文件
  • 将声明和实现写到同一个文件中,并更改后缀名为.hpp (更常用)

Person.hpp

#pragma once
#include <iostream>
using namespace std;template<class NameType, class AgeType = int> // 默认参数为int
class Person
{
public:Person(NameType name, AgeType age);void showPerson();
public:NameType mName;AgeType mAge;
};
// 构造函数 类外实现
template<class NameType, class AgeType>
Person<NameType, AgeType>::Person(NameType name, AgeType age)
{this->mName = name;this->mAge = age;
}
// 成员函数类外实现
template<class NameType, class AgeType>
void Person<NameType, AgeType>::showPerson()
{cout << "name: " << this->mName << " age: " << this->mAge << endl;
}

类模板分文件编写.cpp

#include <iostream>
using namespace std;#include "Person.hpp"int main() {Person<string, int> p("张三", 13);p.showPerson();system("pause");return 0;}
name: 张三 age: 13
请按任意键继续. . .

3.7 类模板和友元

#include <iostream>
using namespace std;
template <class T1,class T2>
class Person;// 2. 全局函数类外实现
template <class T1, class T2>
void showPerson(Person<T1, T2> p) {cout << "姓名:" << p.m_Name << "  年龄:" << p.m_Age << endl;
}template <class T1, class T2>
class Person {// 1. 全局函数类内实现// 加上friend变为全局函数,如果不加的话就是成员函数//friend void showPerson(Person<T1,T2> p) {//	cout << "姓名:" << p.m_Name << "  年龄:" << p.m_Age << endl;//}// 如果全局函数是类外实现,需要让编译器提前知道这个函数存在friend void showPerson<>(Person<T1, T2> p);
public:Person(T1 name, T2 age) {this->m_Name = name;this->m_Age = age;}
private:T1 m_Name;T2 m_Age;
};int main() {Person<string, int> p("Tom", 12);showPerson(p);system("pause");return 0;}
姓名:Tom  年龄:12
请按任意键继续. . .

实战案例
实现一个通用的数组类

  1. 可以对内置数据类型以及自定义数据类型的数据进行存储
  2. 将数组中的数据存储到堆区
  3. 构造函数中可以川入数组的容量
  4. 提供对应的拷贝构造函数以及operator=防止浅拷贝问题
  5. 提供尾插法和尾删法对数组中的数据进行增加和删除
  6. 可以通过下标的方式访问数组中的元素
  7. 可以获取数组中当前元素个数和数组的容量

main.cpp

#include <iostream>
using namespace std;
#include "MyArray.hpp"
class Person {
public:Person() {}Person(string name, int age) {m_name = name;m_age = age;}string getName() {return m_name;}int getAge() {return m_age;}
private:string m_name;int m_age=0;
};void showPerson(Myarray<Person> array,int num) {for (int i = 0; i < num; i++) {cout << "姓名:" << array[i].getName() << "   年龄:"<<array[i].getAge()<<endl;}
}
void showInt(Myarray<int> arr, int num) {for (int i = 0; i < num; i++) {cout << arr[i] << " ";}cout << endl;
}void test() {Myarray<int> arr(10);for (int i = 0; i < 10; i++) {arr.insert_Back(i);}showInt(arr, 10);//Myarray<int> arr2(arr);//Myarray<int> arr3(20);//arr3 = arr;//cout <<"arr3的容量为"<< arr3.get_Mcap() << endl;Myarray<Person> PersonArr(2);Person p1("张三", 12);Person p2("李四", 21);PersonArr.insert_Back(p1);PersonArr.insert_Back(p2);showPerson(PersonArr,2);
}
int main() {test();system("pause");return 0;}

MyArray.hpp

#pragma once
#include <iostream>
using namespace std;template <class T>
class Myarray {
public:// 有参构造Myarray(int cap) {cout << "调用有参构造函数" << endl;//cout << "hello" << endl;this->m_cap = cap;this->pArray = new T[this->m_cap]; // 在堆区开辟this->size = 0;}// 拷贝构造Myarray(Myarray& arr) {//cout << "调用拷贝构造函数" << endl;this->size = arr.size;this->m_cap = arr.m_cap;this->pArray = new T[arr.m_cap];// 将arr中的数据拿过来for (int i = 0; i < arr.size; i++) {this->pArray[i] = arr.pArray[i];}}// 析构函数~Myarray() {if (this->pArray!= NULL) {cout << "调用析构函数" << endl;this->m_cap = 0;this->size = 0;// pArray是个数组  删除时要注意格式delete[] pArray;pArray = NULL;//cout << "删除完成" << endl;}}// 重载=操作运算符Myarray& operator=(const Myarray& arr) {//cout << "调用operator=函数" << endl;// 先判断原来栈区是否有数据if (this->pArray != NULL) {delete[] pArray;pArray = NULL;this->m_cap = 0;this->size = 0;}this->m_cap = arr.m_cap;this->size = arr.size;this->pArray = new T[arr.m_cap];return *this;}// 重载[]操作运算符T& operator[](int index) {return pArray[index];}// 获取数组容量int get_Mcap() {return this->m_cap;}// 获取数组大小int get_Size() {return this->size;}// 获取// 尾插法void insert_Back(T value) {// 判断还有无空间if (this->size == this->m_cap) {cout << "达到插入上限!" << endl;return ;}this->pArray[this->size] = value;this->size++;//return *this;}// 尾删法void pop_Back() {// 判断是否为0if (this->size == 0) {cout << "已达删除上限!" << endl;return;}this->size--;}// 通过下标方式访问元素T& get_index(int index) {if (index<0 || index>this.size) {cout << "索引有无!" << endl;return;}return this->pArray[index];}
private:T* pArray; // 头指针int m_cap; // 容量int size; // 大小
};
调用有参构造函数
0 1 2 3 4 5 6 7 8 9
调用析构函数
调用有参构造函数
姓名:张三   年龄:12
姓名:李四   年龄:21
调用析构函数
调用析构函数
调用析构函数
请按任意键继续. . .

相关文章:

C++提高编程——模板

本专栏记录C学习过程包括C基础以及数据结构和算法&#xff0c;其中第一部分计划时间一个月&#xff0c;主要跟着黑马视频教程&#xff0c;学习路线如下&#xff0c;不定时更新&#xff0c;欢迎关注。 当前章节处于&#xff1a; ---------第1阶段-C基础入门 ---------第2阶段实战…...

单线程、同步、异步、预解析、作用域、隐式全局变量、对象创建、new

单线程 进程 cpu 资源分配的最小单位一个进程可以有多个线程 线程 cpu调度的最小单位线程建立在进程的建立基础上的一次程序的运行单位 线程分为&#xff1a;单线程 多线程 单线程&#xff1a;js是单线程 &#xff08;同一个时间只能完成一个任务&#xff09;多线程&…...

《设计模式的艺术》笔记 - 外观模式

介绍 外观模式中外部与一个子系统的通信通过一个统一的外观角色进行&#xff0c;为子系统中的一组接口提供一个一致的入口。外观模式定义了一个高层接口&#xff0c;这个接口使得子系统更加容易使用。外观模式又称为门面模式&#xff0c;它是一种对象结构型模式。 实现 myclas…...

sql 查询时间范围内的数据

要查询特定时间范围内的数据&#xff0c;您可以使用 SQL 中的 BETWEEN 运算符。以下是一个示例查询&#xff0c;它从名为 your_table 的表中检索在 start_date 和 end_date 之间创建的所有记录&#xff1a; SELECT * FROM your_table WHERE created_date BETWEEN start_date AN…...

TestNG中的@BeforeSuite注释

目录 什么是BeforeSuite注解&#xff1f; BeforeSuite带注释的方法何时执行&#xff1f; BeforeSuite annotation有什么用&#xff1f; 所以&#xff0c;是时候集思广益了 我们可以在一个类中使用多个BeforeSuite注释方法吗&#xff1f; BeforeSuite放在超类上时如何工作…...

[学习笔记]刘知远团队大模型技术与交叉应用L3-Transformer_and_PLMs

RNN存在信息瓶颈的问题。 注意力机制的核心就是在decoder的每一步&#xff0c;都把encoder的所有向量提供给decoder模型。 具体的例子 先获得encoder隐向量的一个注意力分数。 注意力机制的各种变体 一&#xff1a;直接点积 二&#xff1a;中间乘以一个矩阵 三&#xff1a;…...

图像处理工具包Pillow的使用分享

Pillow 是 Python 中一个流行的图像处理库&#xff0c;它是 PIL&#xff08;Python Imaging Library&#xff09;的一个友好的分支版本。Pillow 提供了许多功能&#xff0c;使得图像处理变得容易和方便。下面是一些基本用法和示例&#xff1a; 安装 Pillow 首先&#xff0c;你…...

python进程间通信——命名管道(Named Pipe、FIFO)

文章目录 Python中的命名管道&#xff1a;深入理解进程间通信1. 命名管道简介2. 创建和删除命名管道3. 写入命名管道4. 读取命名管道5. 示例&#xff1a;进程间通信write_to_pipe.pyread_from_pipe.py测试运行 6. 注意事项和限制命名管道的半双工机制命名管道读写任意一方未打开…...

03 OSPF 学习大纲

参考文章 1 初步认识OSPF的大致内容(第三课)-CSDN博客 2...

HJ7 取近似值【C语言】

【华为机试题 HJ7】取近似值 描述输入描述:输出描述:示例1示例2参考代码1参考代码2参考代码3描述 写出一个程序,接受一个正浮点数值,输出该数值的近似整数值。如果小数点后数值大于等于 0.5 ,向上取整;小于 0.5 ,则向下取整。 数据范围:保证输入的数字在 32 位浮点数范…...

php基础学习之常量

php常量的基本概念 常量是在程序运行中的一种不可改变的量&#xff08;数据&#xff09;&#xff0c;常量一旦定义&#xff0c;通常不可改变&#xff08;用户级别&#xff09;。 php常量的定义形式 使用define函数&#xff1a;define("常量名字", 常量值);使用cons…...

2024最新面试经验分享

目录 重点掌握的知识点JavaMySQLRedis 微服务分布式系统项目亮点场景题/设计题短链抢红包多租户 开放性问题自我介绍为什么跳槽团队规模如何带团队如何看待加班职业规划 主要针对Java程序员&#xff0c;当然也包含一些通用的内容。 重点掌握的知识点 需要重点掌握的知识点必须…...

《WebKit 技术内幕》之八(1):硬件加速机制

《WebKit 技术内幕》之八&#xff08;1&#xff09;&#xff1a;硬件加速机制 1 硬件加速基础 1.1 概念 这里说的硬件加速技术是指使用GPU的硬件能力来帮助渲染网页&#xff0c;因为GPU的作用主要是用来绘制3D图形并且性能特别好&#xff0c;这是它的专长所在&#xff0c;它…...

子表单扫码录入,显著节省填写时间

01/17 主要更新模块概览 扫 码 识 别 新 增 字 号 登 录 配 置 匹 配 搜 素 扫码识别 路径&#xff1a;表单设计 >> 字段属性 功能简介 之前对子表单扫码录入&#xff0c;是单独在组件内设置扫码&#xff0c;操作需重新点击扫码功能&#xff0c;手工新增子表数据&a…...

【Redis】Ubuntu安装配置

目录 一、安装Redis 1.1 从APT仓库安装Redis 二、启动&关闭&重启 三、Redis核心配置 3.1 CONFIG命令 3.2 redis.conf文件说明 一、安装Redis 1.1 从APT仓库安装Redis 从APT仓库可以安装最新的Redis稳定版&#xff0c;步骤如下&#xff1a; 【1】安装需要用到的…...

idea远程服务调试

1. 配置idea远程服务调试 这里以 idea 新 ui 为例&#xff0c;首先点击上面的 debug 旁边的三个小圆点&#xff0c;然后在弹出的框框中选择 “Edit”&#xff0c;如下图所示。 然后进入到打开的界面后&#xff0c;点击左上角的 “” 进行添加&#xff0c;找到 “Remote JVM De…...

Google Colab运行Pytorch项目

Google Colab运行Pytorch项目 连接google drive切换到某一文件夹显示当前目录文件安装依赖执行py文件numpy相关numpy.random.randn() 参考文章&#xff1a;文章1 文章2 连接google drive from google.colab import drive import os drive.mount(/content/drive)切换到某一文件…...

Android Studi安卓读写NDEF智能海报源码

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?id615391857885&spma1z10.5-c.w4002-21818769070.11.1f60789ey1EsPH <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmln…...

Demo: 实现PDF加水印以及自定义水印样式

实现PDF加水印以及自定义水印样式 <template><div><button click"previewHandle">预览</button><button click"downFileHandle">下载</button><el-input v-model"watermarkText" /><el-input v-mo…...

每日OJ题_算法_二分查找①_力扣704. 二分查找

目录 二分查找算法原理 力扣704. 二分查找 解析代码 二分查找算法原理 二分查找一种效率较高的查找方法。但是&#xff0c;二分查找要求线性表必须采用顺序存储结构&#xff0c;而且表中元素按关键字有序排列。一般步骤如下&#xff1a; 首先&#xff0c;假设表中元素是按升…...

【Python】--- 基础语法(1)

目录 1.变量和表达式2.变量和类型2.1变量是什么2.2变量的语法2.3变量的类型2.3.1整数2.3.2浮点数&#xff08;小数&#xff09;2.3.3字符串2.3.4布尔2.3.5其他 2.4为什么要有这么多类型2.5动态类型特征 3.注释3.1注释的语法3.2注释的规范 结语 1.变量和表达式 对python的学习就…...

详解gorm中DB对象的clone属性

详解gorm中DB对象的clone属性 Gorm 版本&#xff1a;v1.22.4 Where函数源码 // Where add conditions func (db *DB) Where(query interface{}, args ...interface{}) (tx *DB) {tx db.getInstance()if conds : tx.Statement.BuildCondition(query, args...); len(conds) &…...

数据库(MySQL库表操作)

目录 1.1 SQL语句基础&#xff08;SQL命令&#xff09; 1.1.1 SQL的简介 1.1.2 SQL语句的分类 1.1.3 SQL语句的书写规范 1.2 数据库操作 1.2.1 查看 1.2.2 自建库 1.2.3 切换数据库 1.2.4 删库 1.3 MySQL字符集 1.3.1 MySQL字符集包括&#xff1a; 1.3.2 utf8 和 u…...

内网穿透的应用-如何使用Docker部署Redis数据库并结合内网穿透工具实现公网远程访问

文章目录 前言1. 安装Docker步骤2. 使用docker拉取redis镜像3. 启动redis容器4. 本地连接测试4.1 安装redis图形化界面工具4.2 使用RDM连接测试 5. 公网远程访问本地redis5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主要介绍如何在Ub…...

计算机网络复试

第1章 概述 时延&#xff1a;发送(传输)时延传播时延 链路中每多一个路由器&#xff0c;就增加一个分组的发送时延 第2章 物理层 2.4 编码与调制->编码(基带调制)->曼彻斯特编码 ->带通调制->混合调制->正交振幅调制QAM 信道极限容量 奈氏准则 无噪声最大速…...

Android学习之路(23)组件化框架ARouter的使用

一、功能介绍 支持直接解析标准URL进行跳转&#xff0c;并自动注入参数到目标页面中支持多模块工程使用支持添加多个拦截器&#xff0c;自定义拦截顺序支持依赖注入&#xff0c;可单独作为依赖注入框架使用支持InstantRun支持MultiDex(Google方案)映射关系按组分类、多级管理&…...

HCIA vlan练习

目录 实验拓扑 实验要求 实验步骤 1、交换机创建vlan 2、交换机上的各个接口划分到对应vlan中 3、trunk干道 4、路由器单臂路由 5、路由器DHCP设置 实验测试 华为交换机更换端口连接模式报错处理 实验拓扑 实验要求 根据图划分vlan&#xff0c;并通过DHCP给主机下发…...

Ubuntu下安装Gazebo仿真器

Ubuntu下安装Gazebo仿真器 Gazebo仿真平台通常需要配合ROS使用&#xff0c;因此需要先安装ROS。可以参考ROS安装教程 首先安装一些必要的工具 sudo apt-get update sudo apt-get install lsb-release wget gnupg修改源 sudo wget https://packages.osrfoundation.org/gazebo…...

Chatgpt+Comfyui绘图源码说明及本地部署文档

其他文档地址&#xff1a; ChatgptComfyui绘图源码运营文档 ChatgptComfyui绘图源码线上部署文档 一、源码说明 1、源码目录说明 app_home&#xff1a;app官网源码chatgpt-java&#xff1a;管理后台服务端源码、用户端的服务端源码chatgpt-pc&#xff1a;电脑网页前端源码cha…...

ts中 any 和 unknown 有什么区别,分别什么时候使用

any 和 unknown 都是顶级类型 top type&#xff0c;也就是所有类型的父类型 &#xff08;1&#xff09;any代表任意类型&#xff0c; 是不做任何检查&#xff0c;相当于不使用 ts&#xff0c;不建议使用&#xff0c;使用 a as any as string 之类的&#xff0c;可以让类型检查…...