C++ 类模板

2023-11-04

目录

        1、定义

2、验证类模板生成的类定义

3、非类型参数

4、模板别名

5、模板类

6、多个参数类型

7、类型参数默认值

8、模板类作为模板函数的入参

9、模板具体化

10、成员模板

11、将模板类用作类型参数

12、模板类中的友元


1、定义

     类模板的概念用法同之前讲解过的函数模板是基本一致的,类模板不是一个完整的可以被单独编译的类定义,只是一个模板而已,因为类型对类模板而言是未知的,编译器会根据使用模板的实际类型在编译期生成对应的完整的类定义,然后用该类定义生成对应的类实例。参考如下示例:

#include <iostream>
#include <typeinfo>

using std::cout;

//template表示声明一个模板,class也可以用typename代替,可以有多个参数类型
//Type表示一个类型名,不一定是具体的类名,可以是int这种基本类型或者模板类型
//注意模板类同模板函数都不是具体的类和函数,不能单独编译
//template <class Type>
template <typename Type>
class Stack
{
private:
    Type * items;
    int size;
    int top;
public:
    Stack(int size);
    ~Stack();
    bool isempty();
    bool isfull();
    bool push(Type & item);
    Type & pop();
};

template <class Type>
Stack<Type>::Stack(int size)
{
	this->size=size;
	this->top=0;
	this->items=new Type[size];
	cout<<"Stack(int size) size:"<<size <<",Type:"<<typeid(Type).name() <<"\n";
}

template <class Type>
Stack<Type>::~Stack()
{
	delete[] items;
}

template <class Type>
bool Stack<Type>::isempty()
{
    return top == 0;
}

template <class Type>
bool Stack<Type>::isfull()
{
    return top == size;
}

template <class Type>
bool Stack<Type>::push(Type & item)
{
    if (top < size)
    {
        items[top++] = item;
        return true;
    }
    else
        return false;
}

template <class Type>
Type & Stack<Type>::pop()
{
    if (top > 0)
    {
    	//C++中不能把引用置空,所以这里实际未pop掉
        return items[--top];
    }
    else
    	//C++中没有空引用,引用不能为空
        return items[0];
}

int main(){
	Stack<int> a(5);
	int b=1,c=2,d=3;
	a.push(b);
	a.push(c);
	a.push(d);
    int d2=a.pop();
    int c2=a.pop();
    int b2=a.pop();
    int b3=a.pop();

    cout<<"d2->"<<d2<<"\n";
    cout<<"c2->"<<c2<<"\n";
    cout<<"b2->"<<b2<<"\n";
    cout<<"b3->"<<b3<<"\n";

	return 0;
}

2、验证类模板生成的类定义

      类模板会根据实际使用的类型生成对应类型下的类定义,然后用该类定义生成类实例,怎么验证生成了不同的类定义了?main方法修改如下:

int main(){
	Stack<int> a(3);
	Stack<int> a2(3);
	Stack<double> d(3);
	Stack<double> d2(3);
	return 0;
}

反汇编main方法,结果如下: 

可以看出分别生成了Stack<int> 和Stack<double>两个类定义,他们的构造函数和析构函数的地址是不一样的,而属于同一个类型的a和a2, d和d2调用的构造函数和析构函数的地址是一样的。

3、非类型参数

      模板参数中出现的常量表达式称为非类型参数,如下列示例中的n,非类型参数的类型只能是整形,枚举,引用或者指针,注意模板代码不能修改非类型参数的值,也不能获取非类型参数的地址,因为该参数在编译结束后在生成的类定义中会被替换成常量。非类型参数也是模板参数的一部分,因此类型参数相同而非类型参数不同依然会生成不同的类定义。对于数组这类需要在编译期确认数组大小的场景可以使用非类型参数传递数组大小,从而利用栈帧分配内存,效率更高,适合容量小的数组;如果是利用构造函数传递数组大小则只能通过new在堆内存中分配数组内存,并且需要在析构函数中用delete释放数组内存,适合容量较大的数组场景。如下示例:

#include <iostream>
#include <cstdlib>

using std::cout;

#define TEMP template <class T, int n>

//其中n表示非类型或者表达式参数,n的类型只能是整形,枚举,引用或者指针,且必须是常量表达式
//T相同而n不同将生成两个不同的类定义,如ArrayTP<int,5>,ArrayTP<int,6>
TEMP
class ArrayTP
{
private:
    T ar[n];
public:
    ArrayTP() {};
    explicit ArrayTP(const T & v);
    //重载下标运算符时应该提供两种形式的重载函数,第一种允许修改元素,第二种不允许
    T & operator[](int i);
    //方法后的const表示该方法不修改类成员属性
    T operator[](int i) const;
    void show();
};

TEMP
ArrayTP<T,n>::ArrayTP(const T & v)
{
    for (int i = 0; i < n; i++)
        ar[i] = v;
}

TEMP
T & ArrayTP<T,n>::operator[](int i)
{
    if (i < 0 || i >= n)
    {
        std::cerr << "Error in array limits: " << i
            << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }
    return ar[i];
}

TEMP
T ArrayTP<T,n>::operator[](int i) const
{
    if (i < 0 || i >= n)
    {
        std::cerr << "Error in array limits: " << i
            << " is out of range\n";
        std::exit(EXIT_FAILURE);
    }
    return ar[i]; 
}

TEMP
void ArrayTP<T,n>::show()
{
	for (int i = 0; i < n; i++)
	        cout<<ar[i]<<",";
	cout<<"show end\n";
}



int main(){
	ArrayTP<int,6> a(0);
	a[0]=1;
	a[1]=2;
	a[2]=3;
	a.show();
	return 0;
}

4、模板别名

      使用using指令对类模板重命名,使用typedef或者using指令对类模板的实例重命名,基于上节的ArrayTP示例,main方法修改如下:

//模板重命名,声明必须放在函数外
template<typename U>
	using array = ArrayTP<U,6>;

int main() {

	array<int> a(0);
	a[0] = 1;
	a[1] = 2;
	a[2] = 3;
	a.show();

	//使用typedef或者using对某个模板类重命名
//	typedef ArrayTP<int, 6> arrayi;
	using arrayi=ArrayTP<int, 6> ;
	arrayi b(0);
	b[0] = 1;
	b[1] = 2;
	b[2] = 3;
	b.show();

	return 0;
}

5、模板类

     用类模板生成的类叫做模板类,模板类同正常的类一样可以作为基类被继承,可以作为组件类,可作为其他模板类的类型参数,只是需要注意模板类的类名必须带上明确的类型参数,如上例中的ArrayTP<int,6>视为一个完整的类名。

用作基类的示例:

class IntArray:public ArrayTP<int,10>{
public:
	IntArray();
	int sum();
};

IntArray::IntArray():ArrayTP<int,10>(0){

}

int IntArray::sum(){
	int sum=0;
	for(int i=0;i<10;i++){
		sum+=operator [](i);
	}
	return sum;
}

int main(){
	IntArray a;
	a[0]=1;
	a[1]=2;
	a[2]=3;
	a.show();
	cout<<"sum="<<a.sum()<<"\n";
	return 0;
}

   用作组合类的示例如下:

class IntArray{
private:
	ArrayTP<int,10> array;
public:
	IntArray();
	int sum();
	void set(int i,int val);
	int get(int i);
};

IntArray::IntArray():array(0){

}

int IntArray::sum(){
	int sum=0;
	for(int i=0;i<10;i++){
		sum+=array[i];
	}
	return sum;
}

void IntArray::set(int i,int val){
	array[i]=val;
}
int IntArray::get(int i){
    return array[i];
}

int main(){
	IntArray a;
	a.set(0,1);
	a.set(1,2);
	a.set(2,3);
	cout<<"a.get(2)="<<a.get(2)<<"\n";
	cout<<"sum="<<a.sum()<<"\n";
	return 0;
}

 用作模板类型参数时,如果模板类所属的类模板和目标类模板是同一个则称为模板递归,如下示例:

int main(){
	//其效果跟二维数组类似,第一维是3,第二维是6
	ArrayTP<ArrayTP<double,6>,3> a;
	a[0]=ArrayTP<double,6>(1);
	a[1]=ArrayTP<double,6>(2);
	a[2]=ArrayTP<double,6>(3);
	for(int i=0;i<3;i++){
	   a[i].show();
	}
	return 0;
}

6、多个参数类型

     同函数模板,类模板同样支持多个参数类型,如下示例:

#include <iostream>
#include <string>

#define TEMP template <class T1, class T2,int typeNum>

TEMP
class Pair
{
private:
    T1 a;
    T2 b;
    int type=typeNum;
public:
    T1 & first();
    T2 & second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    int getType() const { return type; }
    Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
    Pair() {}
};

TEMP
T1 & Pair<T1,T2,typeNum>::first()
{
    return a;
}

TEMP
T2 & Pair<T1,T2,typeNum>::second()
{
    return b;
}


int main()
{
   Pair<int ,std::string,11> a(1,"test");
   std::cout<<"first:"<<a.first()<<",second:"<<a.second()<<",type:"<<a.getType()<<"\n";
   return 0; 
}

7、类型参数默认值

     C++允许给类模板的类型参数和非类型参数提供默认值,注意如果全部使用默认值则类模板后面需加上空的<>,表示这是一个模板类,否则编译器将其视为普通的类而找不到该类的定义。模板函数只允许对非类型参数提供默认值,不能对类型参数提供默认值,但是GUN C下无此限制。如下示例:

#include <iostream>
#include <string>

#define TEMP template <class T1, class T2,int typeNum>

template <class T1=int, class T2=std::string,int typeNum=10>
class Pair
{
private:
    T1 a;
    T2 b;
    int type=typeNum;
public:
    T1 & first();
    T2 & second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    int getType() const { return type; }
    Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
    Pair() {}
};

TEMP
T1 & Pair<T1,T2,typeNum>::first()
{
    return a;
}

TEMP
T2 & Pair<T1,T2,typeNum>::second()
{
    return b;
}

template <class T1=int, class T2=std::string,int typeNum=10>
void show(T1 t,T2 t2){
	std::cout<<"T1:"<< t <<",T2:"<<t2<<",type:"<<typeNum<<"\n";
}

int main()
{
   Pair<> a(1,"test");
   std::cout<<"first:"<<a.first()<<",second:"<<a.second()<<",type:"<<a.getType()<<"\n";
   show<>(1,"test2");
   return 0; 
}

8、模板类作为模板函数的入参

      模板类作为模板函数的入参时,模板类的参数类型信息会自动传递到模板函数中,如下示例:

#include <iostream>
#include <string>

#define TEMP template <class T1, class T2,int typeNum>

template <class T1=int, class T2=std::string,int typeNum=10>
class Pair
{
private:
    T1 a;
    T2 b;
    int type=typeNum;
public:
    T1 & first();
    T2 & second();
    T1 first() const { return a; }
    T2 second() const { return b; }
    int getType() const { return type; }
    Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) { }
    Pair() {}
};

TEMP
T1 & Pair<T1,T2,typeNum>::first()
{
    return a;
}

TEMP
T2 & Pair<T1,T2,typeNum>::second()
{
    return b;
}

template <class T1=int, class T2=int,int typeNum=12>
void show(Pair<T1,T2,typeNum> & pair){
	std::cout<<"typeNum:"<<typeNum <<"\n";
	std::cout<<"first:"<<pair.first()<<",second:"<<pair.second()<<",type:"<<pair.getType()<<"\n";
}

int main()
{
   Pair<int ,std::string,11> a(1,"test");
   //如果显示指定,则必须为11,否则报错参数类型匹配错误
   //不显示指定的情况下默认使用入参的参数类型信息
   show<>(a);
   //全部使用默认值时必须带上<>,表示这是一个类模板,否则编译器认为这是一个普通的类而无法解析
   Pair<> b(2,"test2");
   show<>(b);
   return 0; 
}


9、模板具体化

     部分场景下需要改写模板类的实现以定制部分特殊类型的行为,可通过模板具体化即明确指定在使用某种类型下模板类的实现来实现上述需求,有多个类型参数时还允许部分具体化,即只指定部分类型参数。当编译器匹配具体的模板类时会根据当前参数类型选择具体化程度最高的一个模板类,按需生成类定义。

#include <iostream>
#include <string>

#define TEMP template <class T1, class T2>

template <class T1=int, class T2=std::string>
class Pair
{
private:
    T1 a;
    T2 b;
public:
    T1 & first();
    T2 & second();
    Pair(T1 i,T2 j):a(i),b(j){}
};

TEMP
T1 & Pair<T1,T2>::first()
{
    return a;
}

TEMP
T2 & Pair<T1,T2>::second()
{
    return b;
}

//显示具体化,覆盖原来的实现
template <>
class Pair<int,double>
{
private:
    int a;
    double b;
public:
    int & first();
    double & second();
    Pair(int i,double j):a(i),b(j){}
};


int & Pair<int,double>::first(){
	a++;
	return a;
}

double & Pair<int,double>::second(){
    b++;
    return b;
}

//部分具体化,覆盖原来的实现
template <class T1>
class Pair<T1,double>
{
private:
    T1 a;
    double b;
public:
    T1 & first();
    double & second();
    Pair(T1 i,double j):a(i),b(j){}
};

template <class T1>
T1 & Pair<T1,double>::first(){
	a+=2;
	return a;
}

template <class T1>
double & Pair<T1,double>::second(){
    b+=2;
    return b;
}

int main()
{
   using std::cout;
   //优先使用具体化程度最高的实现
   Pair<int,double> a(1,2);
   cout<<"first="<<a.first()<<"\n";
   cout<<"second="<<a.second()<<"\n";

   Pair<double,double> b(1,2);
   cout<<"first="<<b.first()<<"\n";
   cout<<"second="<<b.second()<<"\n";

   Pair<int,int> c(1,2);
   cout<<"first="<<c.first()<<"\n";
   cout<<"second="<<c.second()<<"\n";
   return 0;
}

执行结果如下:

10、成员模板

    模板类或者模板方法本身可以作为结构,类或者模板类的成员,注意模板作为成员时其类型参数与外部的模板类型参数是独立的,可以使用外部的类型参数或者单独定义一个类型参数。如下示例:

#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class beta
{
private:
	//内部模板类
    template <typename V>
    class hold
    {
    private:
        V val;
    public:
        hold(V v  = 0) : val(v) {}
        void show() const { cout << val << endl; }
        V Value() const { return val; }
    };
    hold<T> q;
    hold<int> n;
public:
    beta( T t, int i) : q(t), n(i) {}
    //模板方法
    template<typename U>
    U blab(U u, T t) { return (n.Value() + q.Value()) * u / t; }
    void Show() const { q.show(); n.show();}
};

int main()
{
    beta<double> guy(3.5, 3);
    guy.Show();
    //自动根据参数类型自动将U设为int
    cout << guy.blab(10, 2.3) << endl;
    //显示指定U的类型
    cout << guy.blab<double>(10, 2.3) << endl;
    cout << guy.blab(10.0, 2.3) << endl;
    return 0; 
}

  也可以把将模板成员的定义放在模板类的外面,更能体现两者类型参数的独立性,如下所示:

#include <iostream>
using std::cout;
using std::endl;

//T作用于整个beta模板类,调用该模板类必须指明T的具体类型
template<typename T>
class beta {
private:
	//V作用于hold模板类
	template<typename V>
	class hold;
	hold<T> q;
	hold<int> n;
public:
	beta(T t, int i) :
			q(t), n(i) {
	}
	//U只作用于blab模板方法
	template<typename U>
	U blab(U u, T t);
	void Show() const;
};

template<typename T>
template<typename V>
class beta<T>::hold {
private:
	V val;
public:
	hold(V v = 0) :
			val(v) {
	}
	void show() const {
		cout << val << endl;
	}
	V Value() const {
		return val;
	}
};

template<typename T>
template<typename U>
U beta<T>::blab(U u, T t) {
	return (n.Value() + q.Value()) * u / t;
}

template<typename T>
void beta<T>::Show() const {
	q.show();
	n.show();
}

int main() {
	beta<double> guy(3.5, 3);
	guy.Show();
	//自动根据参数类型自动将U设为int
	cout << guy.blab(10, 2.3) << endl;
	//显示指定U的类型
	cout << guy.blab<double>(10, 2.3) << endl;
	cout << guy.blab(10.0, 2.3) << endl;
	return 0;
}

11、将模板类用作类型参数

      模板类本身可以作为另一个模板类的类型参数,不同于第四节中模板类作为类型参数时实际是隐式实例化的模板类作为类型参数,这里没有隐式实例化,只是表明该参数是模板类类型而已,具体是哪个模板类根据实际传入的模板类类型确认。如下所示:

#include <iostream>

using std::cout;

template <class T>
class Printer{
private:
	T val;
public:
	Printer(T i):val(i){}
	void show();
};

template <class T>
void Printer<T>::show(){
   cout<<"print val="<<val<<"\n";
}

//T是模板类U的类型参数而非Shower模板类的类型参数,U和V才是Shower的类型参数
template <template <typename T> class U,class V>
class Shower
{
private:
	U<V> s1;
	U<double> s2;
public:
    Shower(int i,double j):s1(i),s2(j) {};
    void print();
};

template <template <typename T> class U,class V>
void Shower<U,V>::print(){
	//这里并不知道U的实际类型,所以编写代码时并不知道s1可能有的方法
	//编译时会校验该方法是否存在
	s1.show();
	s2.show();
}
    
int main()
{
    Shower<Printer,int> a(1,1.2);
    a.print();
    return 0; 
}

12、模板类中的友元

       模板类中的友元有三种类型:非模板友元,约束模板友元和非约束模板友元。非模板友元即友元函数不是一个函数模板而是一个明确类型的普通函数;约束模板友元下友元函数是一个函数模板,这里的约束是指友元的参数类型和模板类的参数类型一致下友元才成立;非约束模板友元下友元函数是一个函数模板,友元的参数类型和模板类的参数类型不要求一致,两者是独立的,即模板函数的所有实例是任何一个模板类实例的友元。

  非模板友元的示例如下: 

#include <iostream>
using std::cout;
using std::endl;

template <typename T>
class HasFriend
{
private:
    T item;
    static int ct;
public:
    HasFriend(const T & i) : item(i) {ct++;}
    ~HasFriend()  {ct--; }
    friend void counts();
    //不能写成HasFriend,因为这个类不存在
//    friend void reports(HasFriend &);
    friend void reports(HasFriend<T> &);
};

//只要符合void reports(HasFriend<T> &)的要求都是HasFriend的友元
void reports(HasFriend<int> & hf);
void reports(HasFriend<double> & hf);

template <typename T>
int HasFriend<T>::ct = 0;

//该函数没有参数类型限制,所以改函数是所有HasFriend模板类实例的友元
void counts()
{
    cout << "int count: " << HasFriend<int>::ct << "; ";
    cout << "double count: " << HasFriend<double>::ct << endl;
}


void reports(HasFriend<int> & hf)
{
    cout <<"HasFriend<int>: " << hf.item << endl;
}

void reports(HasFriend<double> & hf)
{
    cout <<"HasFriend<double>: " << hf.item << endl;
}

int main()
{
    cout << "No objects declared: ";
    counts();
    HasFriend<int> hfi1(10);
    cout << "After hfi1 declared: ";
    counts();
    HasFriend<int> hfi2(20);
    cout << "After hfi2 declared: ";
    counts();
    HasFriend<double> hfdb(10.5);
    cout << "After hfdb declared: ";
    counts(); 
    //Eclipse编译器报错有歧义,实际GNU C编译下没有报错
    reports(hfi1);
    reports(hfi2);
    reports(hfdb);
    return 0; 
}

 约束模板友元的示例如下:

#include <iostream>
using std::cout;
using std::endl;

template <typename U> void counts();
template <typename U> void reports(U &);

template <typename T>
class HasFriend
{
private:
    T item;
    static int ct;
public:
    HasFriend(const T & i) : item(i) {ct++;}
    ~HasFriend()  {ct--; }
    //用模板类的T来具体化函数模板,即只有函数模板的类型参数和模板类一致友元才成立
    friend void counts<T>();
    //两种是等价的,<>表示函数模板具体化
//    friend void reports<T>(T &);
    friend void reports<>(T &);
};

template <typename T>
int HasFriend<T>::ct = 0;

//函数模板定义
template <typename U>
void counts()
{
	//HasFriend的参数类型是int,所以只有U是int下友元才成立,如果是double就报错ct是private,不可访问
    cout << "count: " << HasFriend<int>::ct << endl;
    cout << "count: " << HasFriend<U>::ct << endl;
}

template <typename U>
void reports(U & hf)
{
	//在U是double时同上报错item是private,不可访问
	HasFriend<int> a(1);
    cout <<"HasFriend<U>: " <<a.item << endl;
}


int main()
{
    counts<int>();
    //编译报错
//    counts<double>();
	int a=1;
	reports(a);
	double b=2.1;
	//编译报错
//	reports(b);
    return 0; 
}

 非约束模板的友元如下:

#include <iostream>
using std::cout;
using std::endl;

template <typename U> void counts();
template <typename U> void reports(U &);

template <typename T>
class HasFriend
{
private:
    T item;
    static int ct;
public:
    HasFriend(const T & i) : item(i) {ct++;}
    ~HasFriend()  {ct--; }
    //U和T是独立的,即counts函数的任何实例都是HasFriend模板类任何实例的友元
    template <typename U> friend void counts();
    template <typename U> friend void reports(U &);
};

template <typename T>
int HasFriend<T>::ct = 0;

template <typename U>
void counts()
{
    cout << "count: " << HasFriend<int>::ct << endl;
    cout << "count: " << HasFriend<U>::ct << endl;
}

template <typename U>
void reports(U & hf)
{
	HasFriend<int> a(1);
    cout <<"HasFriend<U>: " <<a.item << endl;
}


int main()
{
    counts<int>();
    counts<double>();
	int a=1;
	reports(a);
	double b=2.1;
	reports(b);
    return 0; 
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 类模板 的相关文章

  • 新手学习python语言基础知识第四天

    语言基础 day4 循环 01 for循环 循环 让代码重复执行 代码写一遍 运行的时候可以执行多次 1 for循环 for循环如图 语法 for 变量 in 序列 循环体 说明 for in 关键字 固定写法 变量 写一个变量名 可以是已
  • JAVA ~ FFmpegFrameRecorder用H264编码封装mp4 有声音无图像

    1问题描述 最近公司做的关于摄像机录制视频保存的问题 发送录制了视频上传至服务器中在浏览器上播放有声音无图像 因为自己是这方面的小白 在自己也在前面博客中也分享了rtsp流媒体如何播放及在H5中嵌入vlc 帧抓取图片及录制视频等文章 希望对
  • 使用ai实现后端端口的调用

    一 创建flask框架 1 创建框架提示词 我需要一个flask框架的demo 把端口号改为8080 需要热加载功能 支持在线更改 请给我代码 导入一些依赖库 from flask import Flask render template
  • 视频播放设计测试用例

    功能测试 1 视频资源能否正常获取 无论从服务器后台或者客户端添加 播放是否正常 2 存在多个视频时 能否上下滑动 无论看完未看完 3 如果一个视频涉及另外一个 切换到相应视频能否正常播放 4 视频音量测试 在无声音播放是否 正常声音是否正
  • vue项目 代码中代理 部署后nginx请求代理

    vue项目 代码中代理 vue2 0 文件地址 config index js module exports dev Paths assetsSubDirectory static assetsPublicPath proxyTable 设
  • 金融时间序列分析:Python基于garch模型预测上证指数波动率、计算var和var穿透率、双尾检验

    目录 一 收益率波动效应的分析 1 1 收益率序列平稳性检验 1 2 建立AR p 模型 1 3 Ljung Box混成检验残差序列的相关性 判断是否有ARCH效应 1 4 建立ARCH模型 二 GARCH模型与波动率预测 2 1 建立GA

随机推荐

  • 后端Springboot框架搭建APi接口开发(第一章)

    本文章以IDEA为开发工具 使用SSM框架进行项目编写 第一节 设计并创建数据库 我们用一个简单的用户表进行操作演示 首先创建Data数据库 create database data 创建User数据表 表中包含用户邮箱 用户姓名 用户密码
  • C++ placement new使用

    placement new重载来原来的operator new 且placement new不能被即需重载 placement new是在原有的一块地址上继续创建一个对象 注意对象类型要一致 这样的操作的优势有两个 1 不用花时间在找合适的
  • Anchor DETR

    Anchor DETR Query Design for Transformer Based Detector 2021 9 1 DETR的object query是学习的 没有物理意义也不能解释每个query注意哪 作者认为学习出来的ob
  • 用十条命令在一分钟内检查Linux服务器性能[转]

    概述 通过执行以下命令 可以在1分钟内对系统资源使用情况有个大致的了解 uptime dmesg tail vmstat 1 mpstat P ALL 1 pidstat 1 iostat xz 1 free m sar n DEV 1 s
  • 关于C++中的随机数生成器

    关于C 中的随机数生成器 今天需要生成随机序列来测试代码 记录一下C 中随机数生成器的使用方法 C 中使用random库生成随机数 主要使用两个类 随机数引擎类 调用这个类会生成一个调用运算符 该运算符不接受任何参数 并返回一个随机的uns
  • 你知道两台Linux之间如何传输文件吗?

    你知道两台Linux之间如何传输文件吗 不同的Linux主机之间想要实现文件相互拷贝的方法有三种 第一种 ftp 也就是其中一台Linux安装ftpServer 这样可以另外一台使用ftp的client程序来进行文件的copy 第二种 采用
  • 转载:Java学习路线(完整详细版)超详细

    Java学习路线 第一阶段 Java基础 一 介绍 二 Java开发介绍 三 Java数组 四 Java面向对象 五 异常 六 集合 七 IO流 八 多线程 第二阶段 JavaWeb 一 介绍 二 HTML5 三 CSS3 四 JavaSc
  • 用Java写数据到POST请求

    用Java写数据到POST请求 HTTP POST请求最常见的用途是发送表单参数到服务器 除了发送表单数据 还可以使用POST的消息Body体发送各种数据 如纯文本 XML文档等 本文讲述如何用Java将数据写入POST请求的Body体 j
  • Filter的应用--权限过滤

    因为项目比较长 需要一步步进行实现 所以分解成一个一个需求 一 需求一 1 需求一 可以看某人的权限 同时 可以对这个用户进行权限的修改 2 程序实现 3 程序目录 4 User java 1 package com web 2 3 imp
  • 2023 Google 开发者大会,共创、赋能开发者

    前言 9月6日 2023 Google 开发者大会在上海拉开帷幕 在本次大会 Google 将技术灵感带到了中国 在为期两天的大会中 让我印象最为深刻的是 谷歌帮助中国开发者释放潜能 持续创新 落地创意灵感 不管你是 Mobile 开发者
  • 算子策略如何配,调试宝典帮你忙

    前面几期讲解了网络构建与训练类报错中各类错误的定位解决方法 相信大家应该对于此类问题有一些较为深入的认识了 在深度学习中 当数据集和参数量的规模越来越大 训练所需的时间和硬件资源会随之增加 最后会变成制约训练的瓶颈 分布式并行训练 可以降低
  • JSVC简介之快速入门

    1 JSVC简介 Apache基金会会common 类似于guava 项目下的项目 2 为什么要使用JSVC java应用增加一种启动方式 Java的缺点 只能用main方法启动 应用能使用1024以下端口 为啥tomcat可以指定端口 系
  • python中多线程编程中eoferror_面试官:请你讲讲Python多线程多进程编程

    Python多线程多进程文章目录并行和并发的概念 线程和进程的概念 来点八股文 PythonGIL锁相关以及历史 多线程编程详解 多进程编程详解 重点 一 什么是并行和并发 首先我们来先说一下一个简单的共同点 并行和并发都是完成多任务更加有
  • python QMessageBox设置标签和按钮居中、中文按钮

    from PyQt5 QtCore import Qt from PyQt5 QtWidgets import QApplication QMessageBox QLabel QDialogButtonBox from PyQt5 QtGu
  • IDEA报错 Cannot resolve method ‘xxx‘ in ‘xxx‘

    今天在用Logback做一个小项目的时候 出现了这个bug 一下子给我报了50个错误 如下图所示 后面经过10分钟左右的排查 在网上搜寻解决方式 网上的解决方案差不多有以下三种 1 重装Logback 2 清除IDE缓存 3 重新导包导库
  • 写入位置时发生访问冲突

    写入位置时发生访问冲突是因为待写入的内存空间不能被写入 可能的情况 给野指针赋值 通常在调试的时候 如果一个指针指向的地址为0x00000000那么表示这个指针不指向任何地址 参考文章 1 2
  • Lesson40 FIFO的配置与使用

    摄像头的FIFO配置使用 一 FIFO的基本工作原理讲解 二 Vivado中FIFO IP的添加和基本配置 三 IP文档资料的获取方法 四 编写测试脚本 1 复制 FIFO 的例化模板 2 新建存放FIFO仿真文件的文件夹 3 全部的仿真代
  • 用opencv简单的检测三角形、正方形、圆以及它们的颜色

    源码下载地址点击打开链接 原始图片 检测结果 检测后图片 下面为完整代码 include
  • 【雕爷学编程】Arduino动手做(65)---红外寻迹传感器

    37款传感器与执行器的提法 在网络上广泛流传 其实Arduino能够兼容的传感器模块肯定是不止这37种的 鉴于本人手头积累了一些传感器和执行器模块 依照实践出真知 一定要动手做 的理念 以学习和交流为目的 这里准备逐一动手尝试系列实验 不管
  • C++ 类模板

    目录 1 定义 2 验证类模板生成的类定义 3 非类型参数 4 模板别名 5 模板类 6 多个参数类型 7 类型参数默认值 8 模板类作为模板函数的入参 9 模板具体化 10 成员模板 11 将模板类用作类型参数 12 模板类中的友元 1