c++函数模板STL详解
函数模板
函数模板语法
所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。
凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。
函数模板定义形式
由以下三部分组成: 模板说明 + 函数定义 + 函数模板调用
template < 类型形式参数表 >类型 函数名 (形式参数表)
{//语句序列
}
1.模板说明
template <类型形式参数表>
类型形式参数的形式:
typename T1,typename T2,typename Tn……或class T1,class T2
(typename 和 class的效果完全相等)
2.函数定义
类型 函数名 (形式参数表)
{
}
**注意:**模板说明的类属参数必须在函数定义中出现一次
函数参数表中可以使用类属类型参数,也可以使用一般类型参数
3.模板函数调用
max<int>(a, b); //显式类型调用
max(a, b); //自动数据类型推导
4.函数模板
5.函数模板和函数重载
// demo 15-4.c
#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;
}
*/void main(void){char cNum = 'c';int iNum = 65;//第一种情况,模板函数和普通函数并存,参数类型和普通重载函数更匹配//调用普通函数//Swap(cNum, iNum);//第二种情况 不存在普通函数,函数模板会隐式数据类型转换嘛?//结论:不提供隐式的数据类型转换,必须是严格的匹配//Swap(cNum, iNum);system("pause");return ;
}
函数模板和普通函数区别结论:
两者允许并存
函数模板不允许自动类型转化
普通函数能够进行自动类型转换
// demo 15-5.c
#include <iostream>using namespace std;//第一版
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){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++编译器优先考虑普通函数
3 如果函数模板可以产生一个更好的匹配,那么选择模板
4 可以通过空模板实参列表的语法限定编译器只通过模板匹配
函数模板调用机制
// demo 15-6.c
#include <iostream>
using namespace std;template <typename T>
T Max(T a, T b){return a>b ? a:b;
}int main()
{int x = 1;int y = 2;Max(x, y);float a = 2.0;float b = 3.0;Max(a, b);return 0;
}
*反汇编观察*
// demo.c
#include <iostream>
using namespace std;int Max(int a, int b){return a>b ? a:b;
}
int main()
{int x = 1;int y = 2;Max(x, y);return 0;
}
// demo.S.file "demo.cpp".local _ZStL8__ioinit.comm _ZStL8__ioinit,1,1.text.globl _Z3Maxii.type _Z3Maxii, @function
_Z3Maxii:
.LFB1021:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6movl %edi, -4(%rbp)movl %esi, -8(%rbp)movl -4(%rbp), %eaxcmpl -8(%rbp), %eaxjle .L2movl -4(%rbp), %eaxjmp .L4
.L2:movl -8(%rbp), %eax
.L4:popq %rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1021:.size _Z3Maxii, .-_Z3Maxii.globl main.type main, @function
main:
.LFB1022:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6subq $16, %rspmovl $1, -8(%rbp)movl $2, -4(%rbp)movl -4(%rbp), %edxmovl -8(%rbp), %eaxmovl %edx, %esimovl %eax, %edicall _Z3Maxiimovl $0, %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1022:.size main, .-main.type _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB1023:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6subq $16, %rspmovl %edi, -4(%rbp)movl %esi, -8(%rbp)cmpl $1, -4(%rbp)jne .L9cmpl $65535, -8(%rbp)jne .L9movl $_ZStL8__ioinit, %edicall _ZNSt8ios_base4InitC1Evmovl $__dso_handle, %edxmovl $_ZStL8__ioinit, %esimovl $_ZNSt8ios_base4InitD1Ev, %edicall __cxa_atexit
.L9:nopleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1023:.size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii.type _GLOBAL__sub_I__Z3Maxii, @function
_GLOBAL__sub_I__Z3Maxii:
.LFB1024:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6movl $65535, %esimovl $1, %edicall _Z41__static_initialization_and_destruction_0iipopq %rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1024:.size _GLOBAL__sub_I__Z3Maxii, .-_GLOBAL__sub_I__Z3Maxii.section .init_array,"aw".align 8.quad _GLOBAL__sub_I__Z3Maxii.hidden __dso_handle.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609".section .note.GNU-stack,"",@progbits
// demo_06.cpp
#include <iostream>
using namespace std;template <typename T>
T Max(T a, T b){return a>b ? a:b;
}int main()
{int x = 1;int y = 2;Max(x, y);float a = 2.0;float b = 3.0;Max(a, b);return 0;
}
g++ -S demo_06.cpp -o demo.S
// demo_06.S.file "demo_06.cpp".local _ZStL8__ioinit.comm _ZStL8__ioinit,1,1.text.globl main.type main, @function
main:
.LFB1022:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6subq $32, %rspmovl $1, -16(%rbp)movl $2, -12(%rbp)movl -12(%rbp), %edxmovl -16(%rbp), %eaxmovl %edx, %esimovl %eax, %edicall _Z3MaxIiET_S0_S0_movss .LC0(%rip), %xmm0movss %xmm0, -8(%rbp)movss .LC1(%rip), %xmm0movss %xmm0, -4(%rbp)movss -4(%rbp), %xmm0movl -8(%rbp), %eaxmovaps %xmm0, %xmm1movl %eax, -20(%rbp)movss -20(%rbp), %xmm0call _Z3MaxIfET_S0_S0_movl $0, %eaxleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1022:.size main, .-main.section .text._Z3MaxIiET_S0_S0_,"axG",@progbits,_Z3MaxIiET_S0_S0_,comdat.weak _Z3MaxIiET_S0_S0_.type _Z3MaxIiET_S0_S0_, @function
_Z3MaxIiET_S0_S0_:
.LFB1023:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6movl %edi, -4(%rbp)movl %esi, -8(%rbp)movl -4(%rbp), %eaxcmpl -8(%rbp), %eaxjle .L4movl -4(%rbp), %eaxjmp .L6
.L4:movl -8(%rbp), %eax
.L6:popq %rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1023:.size _Z3MaxIiET_S0_S0_, .-_Z3MaxIiET_S0_S0_.section .text._Z3MaxIfET_S0_S0_,"axG",@progbits,_Z3MaxIfET_S0_S0_,comdat.weak _Z3MaxIfET_S0_S0_.type _Z3MaxIfET_S0_S0_, @function
_Z3MaxIfET_S0_S0_:
.LFB1024:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6movss %xmm0, -4(%rbp)movss %xmm1, -8(%rbp)movss -4(%rbp), %xmm0ucomiss -8(%rbp), %xmm0jbe .L13movss -4(%rbp), %xmm0jmp .L11
.L13:movss -8(%rbp), %xmm0
.L11:popq %rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1024:.size _Z3MaxIfET_S0_S0_, .-_Z3MaxIfET_S0_S0_.text.type _Z41__static_initialization_and_destruction_0ii, @function
_Z41__static_initialization_and_destruction_0ii:
.LFB1025:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6subq $16, %rspmovl %edi, -4(%rbp)movl %esi, -8(%rbp)cmpl $1, -4(%rbp)jne .L16cmpl $65535, -8(%rbp)jne .L16movl $_ZStL8__ioinit, %edicall _ZNSt8ios_base4InitC1Evmovl $__dso_handle, %edxmovl $_ZStL8__ioinit, %esimovl $_ZNSt8ios_base4InitD1Ev, %edicall __cxa_atexit
.L16:nopleave.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1025:.size _Z41__static_initialization_and_destruction_0ii, .-_Z41__static_initialization_and_destruction_0ii.type _GLOBAL__sub_I_main, @function
_GLOBAL__sub_I_main:
.LFB1026:.cfi_startprocpushq %rbp.cfi_def_cfa_offset 16.cfi_offset 6, -16movq %rsp, %rbp.cfi_def_cfa_register 6movl $65535, %esimovl $1, %edicall _Z41__static_initialization_and_destruction_0iipopq %rbp.cfi_def_cfa 7, 8ret.cfi_endproc
.LFE1026:.size _GLOBAL__sub_I_main, .-_GLOBAL__sub_I_main.section .init_array,"aw".align 8.quad _GLOBAL__sub_I_main.section .rodata.align 4
.LC0:.long 1073741824.align 4
.LC1:.long 1077936128.hidden __dso_handle.ident "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609".section .note.GNU-stack,"",@progbits
结论:
- 编译器并不是把函数模板处理成能够处理任意类型的函数
- 编译器从函数模板通过具体类型产生不同的函数
类模板的使用
为什么需要类模板
1.为什么需要类模板
类模板与函数模板的定义和使用类似,有时,有两个或多个类,其功能是相同的,仅仅是数据类型不同,我们可以通过如下面语句声明了一个类模板:
// demo 15-7.c
template <typename T>
class A
{
public:A(T t){this->t = t;}T &getT(){return t;}public:T t;
};
Ø 类模板用于实现类所需数据的类型参数化
Ø 类模板在表示支持多种数据结构显得特别重要,这些数据结构的表示和算法不受所包含的元素类型的影响
类模板的定义
类模板由模板说明和类说明构成
模板说明同函数模板,如下:
*template* <类型形式参数表>
类声明
例如:
template
class ClassName
{
//ClassName 的成员函数
private :
Type DataMember;
}
单个类模板的使用
// demo 15-8.c
#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;
}
继承中类模板的使用
// demo 15-9.c
#include <iostream>using namespace std;//继承中父子类和模板类的结合情况
//1.父类一般类,子类是模板类, 和普通继承的玩法类似
//2.子类是一般类,父类是模板类,继承时必须在子类里实例化父类的类型参数
//3.父类和子类都时模板类时,子类的虚拟的类型可以传递到父类中/*class B
{
public:B(int b){this->b = b;}private:int b;
};
*/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.子类是一般类,父类是模板类,继承时必须在子类里实例化父类的类型参数
3.父类和子类都时模板类时,子类的虚拟的类型可以传递到父类中
类模板的三种表述方式
所有的类模板函数写在类的外部,在一个cpp中
// demo 15-9.c
#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;
};/*
class A
{
public:A(int t=0);int &getT();A operator +(const A &other);void print();private:int 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> 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* <类型形式参数表>
-
类的成员函数前的类限定域说明必须要带上虚拟参数列表
-
返回的变量是模板类的对象时必须带上虚拟参数列表
-
成员函数参数中出现模板类的对象时必须带上虚拟参数列表
-
成员函数内部没有限定
所有的类模板函数写在类的外部,在不同的.h和.cpp中
// demo.h
#pragma oncetemplate <typename T>
class A
{
public:A(T t=0);T &getT();A operator +(const A &other);void print();private:T t;
};
// demo 15-10.c
#include "demo.h"
#include <iostream>using namespace std;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> 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;
}
****注意:****当类模板的声明(.h文件)和实现(.cpp 或.hpp文件)完全分离,因为类模板的特殊实现,我们应在使用类模板时使用#include 包含 实现部分的.cpp 或.hpp文件。
特殊情况- 友元函数
// demo 15-11.c
#include <iostream>using namespace std;template <typename T>
class A
{
public:A(T t=0);//声明一个友元函数,实现对两个A类对象进行加法操作template <typename T>friend A<T> addA(const A<T> &a, const A<T> &b);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 tmp; //类的内部类型可以显示声明也可以不显示tmp.t =this->t + other.t;return tmp;}template <typename T>
void A<T>::print(){cout<<this->t<<endl;
}//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);//cout<<a.getT()<<endl;A<int> tmp = a + b;A<int> tmp1 = addA<int>(a, b);tmp.print();tmp1.print();system("pause");return 0;
}
模板类和静态成员
// demo 15-12.c
#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 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 a(666), b(888);//A tmp = a + b;A<float> c(777), d(999);a.count = 888;cout<<"b.count:"<<b.count<<endl;cout<<"c.count:"<<c.count<<endl;cout<<"d.count:"<<d.count<<endl;c.count = 1000;cout<<"修改后, d.count:"<<d.count<<endl;//tmp.print();system("pause");return 0;
}
类模板使用总计
归纳以上的介绍,可以这样声明和使用类模板:
-
先写出一个实际的类。
-
将此类中准备改变的类型名(如int要改变为float或char)改用一个自己指定的虚拟类型名(如上例中的T)。
-
在类声明前面加入一行,格式为:
template <typename 虚拟类型参数>
如:
template <typename numtype> class A{…}; //类体
-
用类模板定义对象时用以下形式:
类模板名<实际类型名> 对象名;
或 类模板名<实际类型名> 对象名(实参表列);
如:
A<int> cmp;A<int> cmp(3,7);
-
如果在类模板外定义成员函数,应写成类模板形式:
template <typename 虚拟类型参数>
函数类型 类模板名<虚拟类型参数>::成员函数名(函数形参表列) { …}
关于类模板的几点 补充
-
类模板的类型参数可以有一个或多个,每个类型前面都必须加typename 或class,如:
template <typename T1,typename T2>
class someclass
{…};
在定义对象时分别代入实际的类型名,如:
someclass<int, char> object;
-
和使用类一样,使用类模板时要注意其作用域,只有在它的有效作用域内用使用它定义对象。
-
模板类也可以有支持继承,有层次关系,一个类模板可以作为基类,派生出派生模板类。
相关文章:
c++函数模板STL详解
函数模板 函数模板语法 所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体指定,用一个虚拟的类型来代表。这个通用函数就称为函数模板。 凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数…...
Java利用UDP实现简单群聊
一、创建新项目 首先新建一个新的项目,并按如下操作 二、实现代码 界面ChatFrame类 package 群聊; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.net.InetAddress; public abstract class ChatFrame extends JFrame { p…...
fastapi.templating与HTMLResponse
要声明一个模板对象,应将存储html模板的文件夹作为参数提供。在当前工作目录中,我们将创建一个 “templates “目录。 templates Jinja2Templates(directory“templates”) 我们现在要把这个页面的HTML代码渲染成HTMLResponse。让我们修改一下hello()函…...
当初为什么选择计算机这类的行业?
CSDN给了这么一个话题: 还记得当初自己为什么选择计算机? 当初你问我为什么选择计算机,我笑着回答:“因为我梦想成为神奇的码农!我想像编织魔法一样编写程序,创造出炫酷的虚拟世界!”谁知道&…...
tif文件转png、Excel
l利用gdal读取tif中的地理信息和波段数组,然后保存想要的格式即可。 from osgeo import gdal from PIL import Image import numpy as np import cv2 as cv from matplotlib import pyplot as plt# 读取.tif文件 def read_tif(file_path):dataset gdal.Open(file_…...
【PyTorch】训练过程可视化
文章目录 1. 训练过程中的可视化1.1. alive_progress1.2. rich.progress 2. 训练结束后的可视化2.1. tensorboardX2.1.1. 安装2.1.2. 使用 1. 训练过程中的可视化 主要是监控训练的进度。 1.1. alive_progress 安装 pip install alive_progress使用 from alive_progress i…...
深入理解Go语言GC机制
1、Go 1.3之前的标记-清除(mark and sweep)算法 Go 1.3之前的时候主要用的是普通的标记-清除算法,此算法主要由两个主要的步骤: 标记(Mark phase)清除(Sweep phase) 1)…...
qt-C++笔记之组件-分组框QGroupBox
qt-C笔记之组件-分组框QGroupBox code review! 文章目录 qt-C笔记之组件-分组框QGroupBox1.《Qt 6 C开发指南》p752.《Qt 官方文档》3.《Qt 5.12实战》——5.9 分组框控件 1.《Qt 6 C开发指南》p75 2.《Qt 官方文档》 中间段落翻译: 我把示例补充完整: …...
qt 定时器用法
在qt开发中,定时器是我们经常用到的。我们接下来说一下定时器的三种用法,需要注意的是定时器事件是在主线程中触发的,因此在处理耗时操作时应特别小心,以避免阻塞应用程序的事件循环。 1. 三种定时器使用 1.1 QObject的定时器 …...
用23种设计模式打造一个cocos creator的游戏框架----(九)访问者模式
1、模式标准 模式名称:访问者模式 模式分类:行为型 模式意图:将数据操作与数据结构分离,使得在不修改数据结构的前提下,可以添加或改变对数据的操作。 结构图: 适用于: 当你需要对一个复杂对…...
根文件系统初步测试
一. 简介 上一篇文章学习了向所编译生成的根文件系统中加入 lib库文件。文章地址如下: 根文件系统lib库添加与初步测试-CSDN博客 本文继上一篇文章的学习,本文对之前制作的根文件系统进行一次初步测试。 二. 根文件系统初步测试 为了方便测试&#…...
【精选】设计模式——策略设计模式-两种举例说明,具体代码实现
Java策略设计模式 简介 策略设计模式是一种行为型设计模式,它允许在运行时选择算法的行为。 在软件开发中,我们常常需要根据不同情况采取不同的行为。通常的做法是使用大量的条件语句来实现这种灵活性,但这会导致代码变得复杂、难以维护和扩…...
外包干了3个月,技术倒退2年。。。
先说情况,大专毕业,18年通过校招进入湖南某软件公司,干了接近6年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…...
微信小程序:chooseimage从本地相册选择图片或使用相机拍照
文档 https://uniapp.dcloud.net.cn/api/media/image.html#chooseimage https://developers.weixin.qq.com/miniprogram/dev/api/media/image/wx.chooseImage.html 代码示例 const res await uni.chooseImage({count: 1, //默认9sizeType: [original, compressed], //可以…...
「Swift」取消UITableView起始位置在状态栏下方开始
前言:在写页面UI时发现,当隐藏了NavigationBar时,即使UITableView是从(0,0)进行布局,也会一直在手机状态栏下方进行展示布局,而我的想法是希望UITableView可以从状态栏处就进行展示布局 当前页面展示: 问题…...
android高版本适配使用Tools.java
随着android版本的提升,原生Tools不公开并且不能被正常使用,为了延续项目的功能,修改如下: /** Copyright (C) 2006 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License&quo…...
面试官:说说webpack中常见的Loader?解决了什么问题?
面试官:说说webpack中常见的Loader?解决了什么问题? 一、是什么 loader 用于对模块的"源代码"进行转换,在 import 或"加载"模块时预处理文件 webpack做的事情,仅仅是分析出各种模块的依赖关系&a…...
【蓝桥杯省赛真题50】Scratch智能计价器 蓝桥杯scratch图形化编程 中小学生蓝桥杯省赛真题讲解
目录 scratch智能计价器 一、题目要求 编程实现 二、案例分析 1、角色分析...
折半查找(数据结构实训)
题目: 标准输入输出 题目描述: 实现折半查找。要求查找给定的值在数据表中相应的存储位置。本题目假定输入元素均按非降序输入。 输入: 输入包含若干个测试用例,第一行为测试用例个数k。每个测试用例占3行,其中第一行为…...
AR助推制造业智能转型:实时远程协作与可视化引领生产创新
制造商面临着多方面的变革,技术的兴起催生了工业物联网(IIoT),改变了现代工厂的外貌、系统和流程。同时,全球竞争压力和不断变化的员工队伍要求采用新的员工培训方法,并重新审视工人在工厂中的角色。尽管如…...
【用unity实现100个游戏之18】从零开始制作一个类CSGO/CS2、CF第一人称FPS射击游戏——基础篇3(附项目源码)
文章目录 本节最终效果前言素材人物移动音效枪口火焰和开火音效枪口灯光弹孔和火花添加武器随镜头手臂摇摆效果源码完结 本节最终效果 前言 本节主要实现添加音效,和一些特效、武器摆动调整。 素材 素材,为了方便我直接用了unity免费的音效输出&#…...
sed 流式编辑器
使用方式: 1,前置指令 | sed 选项 定址符指令 2,sed 选项 定址符指令 被处理文档 选项: -n 屏蔽默认输出 -i写入文件 -r支持扩展正则 指令: p输出 d删除 s替换 sed -n 1p user //输出第1行 sed -n…...
Linux shell编程学习笔记33:type 命令
目录 0 引言1 type 命令的功能和格式 1.1 type命令的功能1.2 type 命令的格式2 type命令用法实例 2.1用type命令查看shell内置命令(以echo命令为例)2.2 用type命令查看别名(以ls命令为例)2.3 用type命令同时查看shell内置命令和别…...
【数据结构】—红黑树(C++实现)
🎬慕斯主页:修仙—别有洞天 💜本文前置知识: AVL树 ♈️今日夜电波:Letter Song—ヲタみん 1:36━━━━━━️💟──────── 5:35 …...
内衣洗衣机和手洗哪个干净?高性价比内衣洗衣机推荐
通常来说,我们的内衣裤对卫生要求比较高,毕竟是贴身穿的,所以如果和一般的衣物一起洗,就怕会有细菌互相感染。所以很多用户为了内衣裤的卫生都会选择自己手动洗,但手洗一方面很费时间和人力,另一方面又很伤…...
TikTok与互动广告:品牌如何打破传统界限
随着数字时代的蓬勃发展,广告行业也经历了翻天覆地的变革。在这个变革的浪潮中,TikTok作为一款崭新的社交媒体平台,通过其独特的短视频形式为品牌提供了全新的互动广告机会。 本文将深入探讨TikTok与互动广告的结合,以及品牌如何…...
跟着Nature Communications学习Hisat-Trinity-PASA等分析流程
一边学习,一边总结,一边分享! 详细教程请访问: 组学分析流程 本期分析流程 Hisat2-SamtoolsTrinity_GG_denovoPASA… 本期教程文章 题目:Genomic insights into local adaptation and future climate-induced vulnerability of a keystone forest tree in East Asia H…...
Unity中Batching优化的动态合批
文章目录 前言一、动态合批的规则1、材质相同是合批的前提,但是如果是材质实例的话,则一样无法合批。2、支持不同网格的合批3、动态合批需要网格支持的顶点条件二、我们导入一个模型并且制作一个Shader,来测试动态合批1、我们选择模型的 Mesh…...
2022年第十一届数学建模国际赛小美赛B题序列的遗传过程解题全过程文档及程序
2022年第十一届数学建模国际赛小美赛 B题 序列的遗传过程 原题再现: 序列同源性是指DNA、RNA或蛋白质序列之间的生物同源性,根据生命进化史中的共同祖先定义[1]。DNA、RNA或蛋白质之间的同源性通常根据它们的核苷酸或氨基酸序列相似性来推断。显著的相…...
【Linux】静态库与动态库制作及运行原理
Halo,这里是Ppeua。平时主要更新C语言,C,数据结构算法…感兴趣就关注我吧!你定不会失望。 本篇导航 0. 静态库与动态库1. 制作与使用静态库2. 制作与使用动态库3. 动态库是如何被加载到内存?3.1程序地址空间 0. 静态库…...
工具站推荐
自己搭了一个文本工具站 TextTool,包含了常用的文本功能。 我自己比较常用 行转列、列转行、下划线替换的功能。 欢迎各位大佬提意见和建议...
【JS】toFixed()无法精准保留小数的解决方案
情景复现: 发现用 toFiexd() 四舍五入保留小数有时不是很精确,接下来用 a 8.0345,b8.045,举例如下: var a 8.035; console.log(a.toFixed(2)) // 8.04 var b 8.045; console.log(b.toFixed(2)) // 8.04 不难看出…...
vue3版本学习
1,响应式ref或者reactive const aa ref(hello) const bb reactive({ aa: hello, ss: workd }) 2,计算属性 响应式属性经过计算得到的值(ref),放到模板中,只会随着响应式author.books属性变化而变化 const autor …...
【WPF.NET开发】创建简单WPF应用
本文内容 先决条件什么是 WPF?配置 IDE创建项目设计用户界面 (UI)调试并测试应用程序 通过本文你将熟悉在使用 Visual Studio 开发应用程序时可使用的许多工具、对话框和设计器。 你将创建“Hello, World”应用程序、设计 UI、添加代码并调试错误。在此期间&#…...
视频智能分析国标GB28181云平台EasyCVR加密机授权异常是什么原因?
国标GB28181视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等。 近期有用户选择使用加密机进行EasyCVR授…...
Mysql安全之基础合规配置
一、背景 某次某平台进行安全性符合型评估时,列出了数据库相关安全选项,本文特对此记录,以供备忘参考。 二、安全配置 2.1、数据库系统登录时的用户进行身份标识和鉴别; 1)对登录Mysql系统用户的密码复杂度是否有要…...
前后端分离项目跨域请求
一、前端vue项目 在项目中创建request.js文件,添加以下内容 import axios from "axios"; const api axios.create({ //这里配置的是后端服务提供的接口baseURL: "http://localhost:8080/web-demo",timeout: 1000} ); export default api; …...
OpenEuler系统桌面终端设置字体
初始界面 终端的字体间距过大,阅读起来不方便。 调整终端字体 点击菜单,选择“配置文件首选项” 未命名 ---- 文本---- 勾选 自定义字体 ---- 选择 "DejaVu LGC Sans Mono"字体 你也可以根据自己的喜好,选择其他字体。 修改好了…...
repo常用命令解析(持续更新)
1 同步 1.1 将本地仓库更新到最新状态。它会从远程服务器下载最新的代码,并将本地仓库与之同步。如果本地仓库中已经存在某个项目,repo sync会自动检测本地仓库中该项目的版本,并将其更新到最新状态。 类似于git fetch和git merge命令组合使…...
关于小红书商单变现的一些答疑
AI小红书商单训练营也过去1个月了,今天给大家汇总几个常遇到的问题,希望对大家在运营过程中有所帮助。 1.账号封面是否要统一模版? 为了让账号主页呈现整洁美观的效果,建议统一封面设计,视频开头可以设置一个固定画面…...
使用 Kubernetes Agent Server 实现 GitOps
目录 温习 GitOps 极狐GitLab Kubernetes Agent 极狐GitLab GitOps workflow 极狐GitLab KAS 的配置 创建极狐GitLab agent 创建 agent token Kubernetes 上安装 agent(agentk) 极狐GitLab GitOps workflow 实践 写在最后 温习 GitOps GitOps …...
Day12 qt QMianWindow,资源文件,对话框,布局方式,常用ui控件
QMianWindow 概述 QMainWindow 是一个为用户提供主窗口程序的类,包含一个菜单栏( menu bar )、多 个工具栏 (tool bars) 、多个铆接部件 (dock widgets) 、一个状态栏 (status bar) 及 一个中心部件 (central widget) 许多应用程序的基础…...
Python实现广义线性回归模型(statsmodels GLM算法)项目实战
说明:这是一个机器学习实战项目(附带数据代码文档视频讲解),如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 广义线性模型(Generalized Linear Model,简称GLM)是一种广泛应用于回归分析和分类问题的统…...
GNSEC 2022年第8届全球下一代软件工程线上峰会-核心PPT资料下载
一、峰会简介 新一代软件工程是指利用新的理论、方法和技术,在软件开发、部署、运维等过程中,实现软件的可控、可预测、可维护的软件生产方式。它涵盖了多个领域,如软件开发、测试、部署、运维等,旨在提高软件生产效率和质量。 …...
nVisual能为数据中心解决什么问题?
nVisual通过可视化的管理方式,使数据中心管理者能够有效且高效地管理数据中心的资产、线缆、容量、变更;使数据中心管理者能够获得如下问题的答案,以便能够快速做出更好、更明智的决策: 1.资产管理 我们有什么&#x…...
Android--Jetpack--Databinding详解
不经一番寒彻骨,怎得梅花扑鼻香 一,定义 DataBinding, 又名数据绑定,是Android开发中非常重要的基础技术,它可以将UI组件和数据模型连接起来,使得在数据模型发生变化时,UI组件自动更新。是 MVVM 模式在 An…...
Node.js入门指南(完结)
目录 接口 介绍 RESTful json-server 接口测试工具 会话控制 介绍 cookie session token 上一篇文章我们介绍了MongoDB,这一篇文章是Node.js入门指南的最后一篇啦!主要介绍接口以及会话控制。 接口 介绍 接口是前后端通信的桥梁 ࿰…...
MySQL和Java通用加密解密方式
加密方式使用 AES 加密,再转成 Base64。 SQL -- 加密 update your_table set your_columnto_base64(aes_encrypt(your_column, "password"));-- 解密 select aes_decrypt(from_base64(your_column) ,"password") from your_table; 使用原生 …...
若依前端APP版使用教程
1 增加页面流程 新增Page>新增API>新增组件>新增样式>新增路径(page.json) {"path": "pages/mes/pro/feedback/index","style": {"navigationBarTitleText": "工单报工"}} <template><view class&quo…...
2023 年工程师不可错过的 AI 主要发展趋势
从对未来的好奇到关键的企业工具,人工智能的发展证明了它对工程师的价值。不久前,Gartner 预测,采用人工智能工程实践来构建和管理自适应人工智能系统的企业,在实施人工智能模型方面的表现将优于同行至少 25%,这为各组…...