【C++篇】模板

news2025/1/8 11:26:10

友情链接:C/C++系列系统学习目录

知识总结顺序参考C Primer Plus(第六版)和谭浩强老师的C程序设计(第五版)等,内容以书中为标准,同时参考其它各类书籍以及优质文章,以至减少知识点上的错误,同时方便本人的基础复习,也希望能帮助到大家
 
最好的好人,都是犯过错误的过来人;一个人往往因为有一点小小的缺点,将来会变得更好。如有错漏之处,敬请指正,有更好的方法,也希望不吝提出。最好的生活方式就是和努力的大家,一起奔跑在路上


文章目录

  • 🚀一、函数模板
    • ⛳(一)基本用法
    • ⛳(二)函数模板与函数重载
    • ⛳(三)模板的局限性与显示具体化
    • ⛳(四)函数模板机制剖析
  • 🚀二、类模板
    • ⛳(一)基本用法
    • ⛳(二)类模板函数的三种表达描述方式
    • ⛳(三)类模板与友元函数
    • ⛳(四)类模板与静态成员
    • ⛳(五)模板类valarray简介


🚀一、函数模板

// demo 15-2.c
#include <iostream>

using namespace std;
int Max(int a, int b)
{
	return a>b ? a:b;
}

char Max(char a, char b)
{
	return a>b ? a:b;
}
	
float Max(float a, float b)
{
	return a>b ? a:b;
}

void main()
{
    //char a = 'c';
    
    int x = 1;
    int y = 2;
    cout<<"max(1, 2) = "<<Max(x, y)<<endl;
    
    float a = 2.0;
    float b = 3.0;
    cout<<"max(2.0, 3.0) = "<<Max(a, b)<<endl;
    
    system("pause");
    return ;
}

//实际上,以上程序,只需要一个“函数”就可以搞定!
#include <iostream>

using namespace std;

//template 关键字告诉 C++编译器 我要开始泛型编程了,请你不要随意报错
//T - 参数化数据类型
template <typename T>
T Max(T a, T b){
	return a>b ? a:b;
}

/*如果 T 使用 int 类型调用,相当于调用下面这个函数
int Max(int a, int b)
{
	return a>b ? a:b;
}
*/

void main()
{
    //char a = 'c';
    
    int x = 1;
    int y = 2;
    cout<<"max(1, 2) = "<< Max(x, y) <<endl; //实现参数类型的自动推导
    cout<<"max(1, 2) = "<< Max<int>(x, y) <<endl; //显示类型调用
    
    float a = 2.0;
    float b = 3.0;
    cout<<"max(2.0, 3.0) = "<<Max(a, b)<<endl;
    
    system("pause");
    return ;
}

所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。

⛳(一)基本用法

1.函数模板定义形式

由以下三部分组成: 模板说明 + 函数定义 + 函数模板调用

template < 类型形式参数表 >
类型 函数名 (形式参数表)
{
//语句序列
}

//例如:(class可以换成typename)
template <class AnyType>               --》模板说明
void swap(AnyType &a,AnyType &b){
    AnyType temp ;
    temp = a;                          --》函数定义  
    a = b;
    b = temp ;
}

max<int>(a, b); //显式类型调用           --》函数模板调用
max(a, b);      //自动数据类型推导
  • 在标准C++98添加关键字typename之前,C++使用关键字class来创建模板。也就是说,类型形式参数的形式:typename T1 , typename T2 , …… , typename Tn 或 class T1 , class T2 , …… , class Tn(注:typename 和 class 的效果完全等同),用typename使得参数AnyType表示类型这一点更为明显

  • 模板说明的类型参数必须在函数定义中出现一次,函数参数表中可以使用类类型的参数,也可以使用一般类型参数

  • 模板参数列表的参数是否一样、以及个数、返回值是哪个,都由程序员决定:

    template <typename TRtypename T>
    TR ave(T a,T b)
    {  
       return (a+b)/2;
    }
    

2.模板函数:

在这里插入图片描述

⛳(二)函数模板与函数重载

需要多个对不同类型使用同一种算法的函数时,可使用模板,然而,并非所有的类型都使用相同的算法。为满足这种需求,可以像重载常规函数定义那样重载模板定义。和常规重载一样,被重载的模板的函数特征标必须不同。

#include <iostream>
using namespace std;

template <typename T>
void Swap(T &a, T &b){
    T t;
    t = a;
    a = b;
    b = t;
    cout<<"Swap 模板函数被调用了"<<endl;
}


void Swap(char &a, int &b){
    int t;
    t = a;
    a = b;
    b = t;
    cout<<"Swap 普通函数被调用了"<<endl;
}



//第一版
int Max(int a, int b)
{
    cout<<"调用 int Max(int a, int b)"<<endl;
    return a>b ? a:b;
}
	
template<typename T>
T Max(T a, T b)
{
    cout<<"调用 T Max(T a, T b)"<<endl;
    return a>b ? a:b;
}

template <typename T>
T Max(T a, T b, T c){
    cout<<"调用 T Max(T a, T b, T c)"<<endl;
    return Max(Max(a, b), c);
}


//第二版
int Max1(int a, int b)
{
    cout<<"调用 int Max(int a, int b)"<<endl;
    return a>b ? a:b;
}

template<typename T1, typename T2>
T1 Max1(T1 a, T2 b)
{
    cout<<"调用 T Max1(T1 a, T2 b)"<<endl;
    return a>b ? a:b;
}


void main(void){
    char cNum = 'c';
    int iNum = 65;
    Swap(cNum, iNum);    //模板函数和普通函数并存,参数类型和普通重载函数更匹配,调用普通函数
    //Swap(cNum, iNum);  //如果不存在普通函数,函数模板不提供隐式的数据类型转换,必须是严格的匹配
    
    int a = 1;
	int b = 2;
    cout<< "Max(a, b):" << Max(a, b) << endl;   //当函数模板和普通函数都符合调用时,优先选择普通函数
    //Max<>(a, b);  如果显式的使用函数模板,则使用<> 类型列表
    
    char c = 'a';   //如果函数模板会产生更好的匹配,使用函数模板
    Max1(c, a);
    Max(1.0, 2.0);
    Max(3.0, 4.0, 5.0);	

    
    system("pause");
    return ;
}
  1. 函数模板和普通函数区别:

    • 两者允许并存,模板函数和普通函数并存时,参数类型和哪个更匹配就调用哪个;
    • 函数模板不允许自动类型转化,必须是严格的匹配,普通函数能够进行自动类型转换:
  2. 函数模板和普通函数在一起,调用规则:

    • 函数模板可以像普通函数一样被重载

    • C++编译器优先考虑普通函数

    • 如果函数模板可以产生一个更好的匹配,那么选择模板

    • 可以通过空模板实参列表的语法限定编译器只通过模板匹配:

      Max<>(a, b);
      

⛳(三)模板的局限性与显示具体化

假设有如下函数模板:

template <class T>
void f(T a, T b)
{
	a = b;
}
  1. 局限性:

如果T为数组,这种假设就不成立了,如果里面的语句为判断语句 if(a>b),但T如果是结构体,该假设也不成立,另外如果是传入的数组,数组名为地址,因此它比较的是地址,而这也不是我们所希望的操作。

总之,编写的模板函数很可能无法处理某些类型,为了解决这种问题,对于结构体等,一种解决方案是,C++允许您重载运算符+,以便能够将其用于特定的结构或类,另一种解决方案是,可以提供模板的重载,为这些特定的类型提供具体化的模板。

  1. 显示具体化:
class Person
{
public:
    Person(string name, int age)
    {
        this->mName = name;
        this->mAge = age;
    }
    string mName;
    int mAge;
};

//普通交换函数
template <class T>
void mySwap(T &a,T &b)
{
    T temp = a;
    a = b; 
    b = temp;
}

//第三代具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型
//具体化优先于常规模板
template<> void mySwap<Person>(Person &p1, Person &p2)
{
    string nameTemp;
    int ageTemp;

    nameTemp = p1.mName;
    p1.mName = p2.mName;
    p2.mName = nameTemp;

    ageTemp = p1.mAge;
    p1.mAge = p2.mAge;
    p2.mAge = ageTemp;

}

void test()
{
    Person P1("Tom", 10);
    Person P2("Jerry", 20);

    cout << "P1 Name = " << P1.mName << " P1 Age = " << P1.mAge << endl;
    cout << "P2 Name = " << P2.mName << " P2 Age = " << P2.mAge << endl;
    mySwap(P1, P2);
    cout << "P1 Name = " << P1.mName << " P1 Age = " << P1.mAge << endl;
    cout << "P2 Name = " << P2.mName << " P2 Age = " << P2.mAge << endl;
}
  • 试验其他具体化方法后,C++98标准(第三代具体化)选择了下面的方法。对于给定的函数名,可以有非模板函数、模板函数和显式具体化模板函数以及它们的重载版本。显式具体化的原型和定义应以template<>打头,并通过名称来指出类型。

  • 如果有多个原型,则编译器在选择原型时,非模板函数优先于显式具体化和模板函数,而显式具体化优先于使用函数模板生成的版本:

    ...
    template <class T>   // template
    void Swap(T &,T &);
    
    //explicit specialization for the job type
    template <> void Swap<job>(job &, job &) ;
    int main()
    {
        double u,v;
        ...
        Swap(u,v); // use template
        job a, b;
        Swap(a, b) // use void Swap<job>(job &, job&)
    }
    

    第一次将调用Swap( )时使用通用版本,而第二次调用使用基于job类型的显式具体化版本。

  • Swap<job>中的<job>是可选的,因为函数的参数类型表明,这是job的一个具体化。因此,该原型也可以这样编写:

    template <> void Swap(job &, job &) ;
    

⛳(四)函数模板机制剖析

  1. 实例化和具体化:

    • 实例化即使用某种类型,调用模板生成一个此函数的实例,例如上面的Swap(u,v);
    • 具体化则是为了某些特殊类型,提供模板的重载,为这些特定的类型提供具体化的模板。
  2. 编译器并不是把函数模板处理成能够处理任意类型的函数而是编译器从函数模板通过具体类型产生不同的函数

    • 注意,函数模板不能缩短可执行程序。如果有两个实例化函数,最终仍将由两个独立的函数定义,就像以手工方式定义了这些函数一样。最终的代码不包含任何模板,而只包含了为程序生成的实际函数。使用模板的好处是,它使生成多个函数定义更简单、更可靠。
    • 在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,得到的是模板实例(instantiation)。
  3. 可用通过<>显示进行模板的调用,称为显示具体化,注意:以此方式,参数可以进行类型转换,相当于强制类型转换:

    template <class T>
    T Add(T a,T b) // pass by value{
    	return a + b;
    }
    ...
    int m = 6 ;
    double x = 10. 2 ;
    cout << Add<double> (x,m) << endl; // explicit instantiation
    

    这里的模板与函数调用Add(x, m)不匹配,因为该模板要求两个函数参数的类型相同。但通过使用Add<double>(x, m),可强制为double类型实例化,并将参数m强制转换为double类型,以便与函数Add<double>(double, double)的第二个参数匹配。

    引入显式实例化后,必须使用新的语法——在声明中使用前缀template <>,以区分显式实例化和显式具体化。

    如果对Swap做类似的处理,结果将如何呢?

    void Swap(T &,T &);
    
    int m = 5;
    double x = 14. 3 ;
    Swap<double>(m, x); // almost works
    

    这将为类型double生成一个显式实例化。不幸的是,这些代码不管用,因为第一个形参的类型为double &,不能指向int变量m。

🚀二、类模板

template <typename T>
class A
{
public:
	A(T t)
    {
    	this->t = t;
    }
    
    T &getT()
    {
    	return t;
    }
public:
	T t;
};

类模板与函数模板的定义和使用类似,有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同

⛳(一)基本用法

1.类模板定义形式:

类模板由模板说明和类说明构成

//模板说明同函数模板,如下:
template <类型形式参数表>
类声明
    
    
//例如:
template <typename Type>
class ClassName
{
	//ClassName 的成员函数
private :
	Type DataMember;
}
  • 类模板用于实现类所需数据的类型参数化,类模板在表示支持多种数据结构显得特别重要,这些数据结构的表示和算法不受所

    包含的元素类型的影响

2.单个类模板的使用:

#include <iostream>
using namespace std;

template <typename T>
class A
{
public:
	//函数的参数列表使用虚拟类型
    A(T t=0)
    {
    	this->t = t;
    }
    //成员函数返回值使用虚拟类型
    T &getT()
    {
    	return t;
    }
    
private:
    //成员变量使用虚拟类型
    T t;
};

void printA(A<int> &a){
	cout<<a.getT()<<endl;
}

int main(void){
    //1.模板类定义类对象,必须显示指定类型
    //2.模板类如果使用了构造函数,则遵守以前的类的构造函数的调用规则
    A<int> a(666);
    cout<<a.getT()<<endl;
    
    //模板类做为函数参数
    printA(a);
    system("pause");
    return 0;
}

3.继承中类模板的使用:

#include <iostream>
using namespace std;


template <typename T>
class A
{
public:
    //函数的参数列表使用虚拟类型
    A(T t)
    {
    	this->t = t;
    }
    //成员函数返回值使用虚拟类型
    T &getT()
    {
    	return t;
    }
private:
//成员变量使用虚拟类型
	T t;
};

template <typename Tb>
class B: public A<int>  //要实例化父类的类型参数
{
public:
    B(Tb b):A<Tb>(b)
    {
    	this->b = b;
    }
private:
	Tb b;
};

void printA(A<int> &a){  
	cout<<a.getT()<<endl;
}

int main(void){
    //1.模板类定义类对象,必须显示指定类型
    //2.模板种如果使用了构造函数,则遵守以前的类的构造函数的调用规则
    A<int> a(666);
    cout<<a.getT()<<endl;
    
    B<int> b(888);
    cout<<"b(888): "<<b.getT()<<endl;
    
    //模板类做为函数参数
    printA(a);
    system("pause");
    return 0;
}

父类是一般类,子类是模板类, 和普通继承的玩法类似;子类是一般类,父类是模板类,继承时必须在子类里实例化父类的类型参数;父类和子类都时模板类时,子类的虚拟的类型可以传递到父类中

⛳(二)类模板函数的三种表达描述方式

  1. 所有的类模板函数写在类的内部,如以上代码所示

  2. 所有的类模板函数写在类的外部,在一个 cpp 中:

    #include <iostream>
    using namespace std;
    template <typename T>
    class A
    {
    public:
    	A(T t=0);
    	T& getT();
    	A operator +(const A &other);
    	
    	void print();
    private:
    	T t;
    };
    
    template <typename T>
    A<T>::A(T t)
    {
    this->t = t;
    }
    
    template <typename T>
    T& A<T>::getT()
    {
    	return t;
    }
    
    template <typename T>
    A<T> A<T>::operator+(const A<T> &other){  //第一个A<T>是因为返回类型是模板类对象,第二个A<T>是因为是类限定域说明,第三个是因为参数是模板类对象
        A<T> tmp; //类的内部类型可以显示声明也可以不显示
        tmp.t =this->t + other.t;
        return tmp;
    }
    
    template <typename T>
    void A<T>::print(){
    	cout<< this->t <<endl;
    }
    
    int main(void){
        A<int> a(666), b(888);
        //cout<<a.getT()<<endl;
        
        A<int> tmp = a + b;
        
        tmp.print();
        
        system("pause");
        return 0;
    }
    

    在同一个 cpp 文件中把模板类的成员函数放到类的外部,需要注意以下几点:

    • 函数前声明 template <类型形式参数表>
    • 类的成员函数前的类限定域说明必须要带上虚拟参数列表
    • 返回的变量是模板类的对象时必须带上虚拟参数列表
    • 成员函数参数中出现模板类的对象时必须带上虚拟参数列表
  3. 所有的类模板函数写在类的外部,在不同的.h和.cpp中

注意:当类模板的声明(.h 文件)和实现(.cpp 或.hpp 文件)完全分离,因为类模板的特殊实现,我们应在使用类模板时使用#include 包含 实现部分的.cpp 或.hpp 文件。即在main.cpp中使用#include "demo.cpp"而不是.h文件

⛳(三)类模板与友元函数

#include <iostream>

using namespace std;

template <typename T>
class A
{
public:
	...
	//声明一个友元函数,实现对两个 A 类对象进行加法操作
    template <typename T>
    friend A<T> addA(const A<T> &a, const A<T> &b);

private:
	T t;
};


//A 类的友元函数,就是它的好朋友
template <typename T>
A<T> addA(const A<T> &a, const A<T> &b){
    A<T> tmp;
    cout<<"call addA()..."<<endl;
    tmp.t = a.t + b.t;
    return tmp;
}

int main(void){
    A<int> a(666), b(888);
    
    A<int> tmp = a + b;
    A<int> tmp1 = addA<int>(a, b);
    tmp.print();
    tmp1.print();
    
    system("pause");
    return 0;
}
  • 类内部声明友元函数,必须写成以下形式:

    template<typename T>
    friend A<T> addA (A<T> &a, A<T> &b);
    
  • 友元函数实现 必须写成:

    template<typename T>
    A<T> add(A<T> &a, A<T> &b)
    {
    	//......
    }
    
  • 友元函数调用 必须写成

    A<int> c4 = addA<int>(c1, c2);
    

⛳(四)类模板与静态成员

#include <iostream>
using namespace std;
template <typename T>
class A
{
public:
	A(T t=0);
	T& getT();
	A operator +(const A &other);
	
	void print();
public:
    static int count;
private:
	T t;
};

template <typename T> int A<T>::count = 666;

template <typename T>
A<T>::A(T t)
{
this->t = t;
}

template <typename T>
T& A<T>::getT()
{
	return t;
}

template <typename T>
A<T> A<T>::operator+(const A<T> &other){  //第一个A<T>是因为返回类型是模板类对象,第二个A<T>是因为是类限定域说明,第三个是因为参数是模板类对象
    A<T> tmp; //类的内部类型可以显示声明也可以不显示
    tmp.t =this->t + other.t;
    return tmp;
}

template <typename T>
void A<T>::print(){
	cout<< this->t <<endl;
}



//当我们的虚拟的类型 T 被 int 实例化以后,模板类如下:
class A
{
public:
    A(int t=0);
    int &getT();
    A operator +(const A &other);
    void print();
public:
	static int count;
private:
	int t;
};

int A::count = 666;

A::A(int t)
{
	this->t = t;
}

int &A::getT()
{
	return t;
}

A A::operator+(const A &other){
    A tmp; //类的内部类型可以显示声明也可以不显示
    tmp.t =this->t + other.t;
    return tmp;
}

void A::print(){
    cout<<this->t<<endl;
}

//当我们的虚拟的类型 T 被 float 实例化以后,模板类如下:
class A
{
public:
    A(float t=0);
    float &getT();
    A operator +(const A &other);
    void print();
public:
	static int count;
private:
	float t;
};

int A::count = 666;

A::A(float t)
{
	this->t = t;
}

float &A::getT()
{
	return t;
}

A A::operator+(const A &other){
    A tmp; //类的内部类型可以显示声明也可以不显示
    tmp.t =this->t + other.t;
    return tmp;
}

void A::print(){
	cout<<this->t<<endl;
}

int main(void){
    A<int> a(666), b(888);
    A<int> tmp = a + b;
    
    A<float> c(777), d(999);
    
    a.count = 888;
    
    cout<<"b.count:"<<b.count<<endl;  //888
    
    cout<<"c.count:"<<c.count<<endl; //666
    cout<<"d.count:"<<d.count<<endl; //666
    c.count = 1000; 
    cout<<"修改后, d.count:"<<d.count<<endl; //1000
    
    
    system("pause");
    return 0;
}
  • 从类模板实例化的每个模板类有自己的类模板数据成员,该模板类的所有对象共享一个 static 数据成员

  • 和非模板类的 static 数据成员一样,模板类的 static 数据成员也应该在文件范围定义和初始化

  • static 数据成员也可以使用虚拟类型参数T:static T count

  • 和函数模板一样,类模板的类型参数可以有一个或多个,每个类型前面都必须加 typename 或 class,如:

    template <typename T1,typename T2>
    class someclass
    {...};
    //在定义对象时分别代入实际的类型名,如:
    someclass<int, char> object;
    
  • 和使用类一样,使用类模板时要注意其作用域,只有在它的有效作用域内用使用它定义对象。

⛳(五)模板类valarray简介

  1. valarray类是由头文件varlarray支持的。用于处理数值,支持诸如将数组中所有元素的值相加以及在数组中找出最大和最小的值操作。

  2. valarray被定义为一个模板类,以便能够处理不同的数据类型。

  3. 模板特性意味着声明对象,必须指定具体的数据类型。因此,使用valarray类来声明一个对象时,需要在标识符valarray后面加上一对尖括号,并在其中包含所需的数据类型:

    valarray<int> q_values;// int数组
    valarray<double> weights;//double数组
    

类特性意味着要使用valarray对象,需要了解这个类的构造函数和其它用法。下面是几个使用其构造函数的例子:

double gpa[5]={3.1,3.5,3.8,2.9,3.3};
valarray<double> v1;       //一个double类型的数组,长度为0
valarray<int> v2(8);       //一个int类型的数组,长度为8
valarray<int> v3(10,8);    //含8个int元素的数组;每个设置为10
valarray<double>v4(gpa,4); //由4个元素组成的数组,初始化为gpa的前4个元素
//即第二个参数指定数组长度,第一个参数设置元素值

//在c++11中,也可使用初始化列表:
valarray<int> v5={20,32,17,9};//c++11

下面是这个类的一些方法:

  • operator[]():让您能够访问各个元素。
  • size():返回包含的元素数。
  • sum():返回所有元素的总和
  • max():返回最大的元素
  • min():返回最小的元素

行文至此,落笔为终。文末搁笔,思绪驳杂。只道谢不道别。早晚复相逢,且祝诸君平安喜乐,万事顺意。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/672658.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用 InstructPix2Pix 对 Stable Diffusion 进行指令微调

本文主要探讨如何使用指令微调的方法教会 Stable Diffusion 按照指令 PS 图像。这样&#xff0c;我们 Stable Diffusion 就能听得懂人话&#xff0c;并根据要求对输入图像进行相应操作&#xff0c;如: 将输入的自然图像卡通化 。 图 1&#xff1a;我们探索了 Stable Diffusion …

深入探索Android应用启动原理:从入口到界面展示

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想…

day12_面向对象的三大特征之一(封装)

封装概述​​​​​​​ 为什么需要封装&#xff1f; 现实生活中&#xff0c;每一个个体与个体之间是有边界的&#xff0c;每一个团体与团体之间是有边界的&#xff0c;而同一个个体、团体内部的信息是互通的&#xff0c;只是对外有所隐瞒。例如&#xff1a;我们使用的电脑&a…

【从删库到跑路】MySQL数据库的查询(单表查询,多表查询,内外连接,联合查询,子查询)

&#x1f38a;专栏【MySQL】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 大一同学小吉&#xff0c;欢迎并且感谢大家指出我的问题&#x1f970; 文章目录 &#x1f354;多表查询⭐多表关系&#x1f388;一对多&#x…

自动化运维工具-Ansible详解

目录 一、Ansible介绍 &#xff08;一&#xff09;简介 &#xff08;二&#xff09;特性 &#xff08;三&#xff09;优势 &#xff08;四&#xff09;基本架构 &#xff08;五&#xff09;任务执行模式 &#xff08;六&#xff09;ansible与其余配置管理软件的对比 二、…

【C++篇】STL标准模板库

友情链接&#xff1a;C/C系列系统学习目录 知识点内容正确性以C Primer&#xff08;中文版第五版&#xff09;、C Primer Plus&#xff08;中文版第六版&#xff09;为标准&#xff0c;同时参考其它各类书籍、优质文章等&#xff0c;总结归纳出个人认为较有逻辑的整体框架&…

SpringCloud Alibaba入门1之创建多模块工程

一、创建父项目 创建一个父Maven项目&#xff0c;项目命名为myshop,用于管理子模块。 创建项目后&#xff0c;删除src和增加pom设置 二、创建子module 右键父项目&#xff0c;新建module 此我们的子module就创建完成了。接下来如法炮制&#xff0c;创建另外几个子module&…

【Python 基础篇】Python 元组及元组常用函数

文章目录 导言一、什么是元组二、创建元组2.1 使用括号创建元组2.2 使用函数创建元组 三、访问元组元素四、元组常用函数4.1 len()4.2 count()4.3 index() 总结 导言 当我们需要存储一组不可变的数据时&#xff0c;Python中的元组&#xff08;Tuple&#xff09;就派上了用场。…

chatgpt赋能python:Python文件与目录

Python文件与目录 Python拥有强大的文件和目录操作功能&#xff0c;这使得它成为一个非常强大的编程语言之一。Python的文件和目录操作功能可以帮助你创建、读取和写入文件&#xff0c;访问和处理目录结构&#xff0c;以及对文件和目录进行各种操作。 在这篇文章中&#xff0…

jmeter连接数据mysql数据库

1. 数据库驱动下载 下载地址&#xff1a;https://dev.mysql.com/downloads/connector/j/5.1.html 将下载后的 mysql-connector-java-8.0.27.jar 包放到jmeter的lib目录下 2. 创建jdbc connnection configuration jdbc:mysql://43.224.3.131:3360/student?allowMultiQueriest…

【C++篇】C++与C小知识点区别

友情链接&#xff1a;C/C系列系统学习目录 知识点内容正确性以C Primer&#xff08;中文版第五版&#xff09;、C Primer Plus&#xff08;中文版第六版&#xff09;为标准&#xff0c;同时参考其它各类书籍、优质文章等&#xff0c;总结归纳出个人认为较有逻辑的整体框架&…

2023-01-06 LightDB单机安装.md

LightDB单机安装 LightDB官网&#xff1a;https://www.hs.net/lightdb 下载安装包&#xff1a;lightdb-x-13.8-22.3-7953-el7.x86_64.zip 前置准备 防火墙配置(选择一种操作) firewall防火墙 firewall-cmd --permanent --add-port5432/tcp firewall-cmd --permanent --add-port…

【Unity Shader】从入门到感慨(2)用C#画一个立方体

文章目录 一、构成一个立方需要多少个顶点?二、定义三角面的索引数组:三、定义UV坐标数组:四、最后构建Mesh:五、完整代码:一、构成一个立方需要多少个顶点? 这个问题是面试经常被问到的题。如上图,我们知道在几何中立方体有6个面,8个顶点。但在图形学中,顶点指的是模…

神经网络:卷积操作

当谈到计算机视觉中的网络模型结构时&#xff0c;卷积操作是其中一个关键的组成部分。卷积操作是一种基于局部区域的操作&#xff0c;它在计算机视觉中用于图像处理和特征提取。 卷积操作的原理如下&#xff1a; 给定一个输入图像和一个称为卷积核&#xff08;或滤波器&#x…

HCIP网络笔记分享——IA回顾及OSPF协议

第一部分 HCIA回顾1、网络基础2、动态路由协议3、路由认证4、路由控制&#xff08;AD metric &#xff09; 一、知识巩固二、场景模拟1、获取IP地址1.1 DHCP --- 动态主机配置协议1.1.1 DHCP客户端1.1.2 DHCP服务器1.1.3 DHCP客户端1.1.4 DHCP服务器 2、打开浏览器3、路由器进行…

QT 多语言 中英文切换

本文详细的介绍了利用Qt语言大师工具&#xff0c;实现Qt程序的多国家语言切换。例如新建界面、pro参数、更新翻译、QT预言家翻译语言、翻译中文、翻译英文、发布翻译、核心代码、h源代码、cpp源代码、演示效果等操作。 本文作者原创&#xff0c;转载请附上文章出处与本文链接…

chatgpt赋能python:Python文件怎么建立?

Python文件怎么建立&#xff1f; 对于有经验的Python开发人员&#xff0c;创建文件是一个基本的任务。在这篇文章中&#xff0c;我们将讨论如何创建Python文件&#xff0c;包括使用文本编辑器、命令行和集成开发环境&#xff08;IDE&#xff09;。 通过文本编辑器创建Python文…

【在线商城系统】数据来源-爬虫篇

系列文章目录 【在线商城系统】数据来源-爬虫篇 文章目录 系列文章目录前言1、目标2、系统设计3、系统功能3.1、数据建模3.2、数据处理层系统3.2.1、创建Springboot项目3.2.1.1、配置依赖3.2.1.2、Selenium辅助类3.2.1.3、商品分类、商品详情实体类 3.2.2、获取数据3.2.3、获取…

【C++篇】继承和派生

友情链接&#xff1a;C/C系列系统学习目录 知识总结顺序参考C Primer Plus&#xff08;第六版&#xff09;和谭浩强老师的C程序设计&#xff08;第五版&#xff09;等&#xff0c;内容以书中为标准&#xff0c;同时参考其它各类书籍以及优质文章&#xff0c;以至减少知识点上的…

不用手动改 package.json 的版本号

“为什么package.json 里的版本还是原来的&#xff0c;有没有更新&#xff1f;”&#xff0c;这个时候我意识到&#xff0c;我们完全没有必要在每次发布的时候还特意去关注这个仓库的版本号&#xff0c;只要在发布打tag的时候同步一下即可 node.js 部分&#xff0c;我们得有一个…