03-C++ 类和对象

类和对象

1. 概述

1.1 对象

真实存在的事物

1.2 类

多个对象抽取其共同特点形成的概念静态特征提取出来的概念称为成员变量,又名属性
动态特征提取出来的概念称为成员函数,又名方法

1.3 类与对象的关系

在代码中先有类后有对象
一个类可以有多个对象
多个对象可以属于同一个类

2. 类的定义

2.1 语法

class 类名
{[访问权限修饰符:]成员变量成员函数
};

2.2 访问权限修饰符

private: 私有的,当前类中可用,默认的protected: 受保护的,当前类或子类中可用public: 公共的,当前项目中可用

2.3 示例

class Person{
private:int age;
protected:char sex[10];
public:char name[50];void eat(){cout << name << "吃饭" << endl;} void sleep();
};void Person::sleep()
{ cout << name << "睡觉" << endl;
}

3. 封装性

概念:即包装,将数据和方法封装在一起,加以权限区分使其可以保护内部,降低耦合度,便于使用

int a = 10;
int nums[5] = {1,2,3,4,5};
void fun()
{xxx
} 
class A
{属性函数
} 
A a;
x.c文件

优点:

  1. 降低代码耦合度
  2. 提高代码复用率
  3. 便于使用

4. 类的设计

① 私有化所有属性

② 提供可以获取这些属性值与修改属性值的函数

示例:

#include <iostream>
#include <cstring>using namespace std;class Dog{
private:char name[30];int age;
public:void set_name(char *n){strcpy(name, n);}void set_age(int a){age = a;}char *get_name(){return name;}int get_age(){return age;}void look_dor(){cout << name << "看门" << endl;}void eat(){cout << name << "吃" << endl;}
};int main(int argc, char *argv[])
{Dog d1;d1.set_name("大黄");d1.set_age(2);char *name = d1.get_name();int age = d1.get_age();cout << "姓名:" << name << " 年龄:" << age<< endl;d1.look_dor();Dog d2;d2.set_name("旺财");d2.set_age(1);char *name2 = d2.get_name();int age2 = d2.get_age();cout << "姓名:" << name2 << " 年龄:" << age2 << endl;d2.eat();return 0;
}
//姓名:大黄 年龄:2
//大黄看门
//姓名:旺财 年龄:1
//旺财吃

4.1 练习

请设计一个 Person 类,Person 类具有 name 和 age 属性,提供初始化函数(Init)
并提供对 name 和 age 的读写函数(set,get)
但必须确保 age 的赋值在有效范围内(0-100),超出有效范围,则拒绝赋值
并提供方法输出姓名和年龄
#include <iostream>
#include <cstring>
using namespace std;
class Person
{
private:char name[50];int age;
public:void init(char *n,int a){strcpy(name,n);if(a < 0 || a > 100){age = 0;return;}age = a;}void set_name(char *n){strcpy(name,n);}char* get_name(){return name;}void set_age(int a){if(a < 0 || a > 100){age = 0;return;}age = a;}void print_info(){cout << name << endl << age << endl;}
};
int main(int argc, char *argv[])
{Person p;
//    strcpy(p.name,"德玛");
//    p.age = -18;p.set_name("德玛");p.set_age(-18);p.print_info();Person p2;p2.init("光头强",18);p2.print_info();return 0;
}
//德玛
//0
//光头强
//18

4.2 练习2:分文件

设计立方体类(Cube)
其属性有长,宽,高
其函数有获取长宽高的函数,修改长宽高的函数
计算体积的函数
计算面积的函数提示:立方体的面积:2ab + 2ac + 2bc体积:a * b * c

main.cpp 文件:

#include <iostream>
#include "cude.h"
using namespace std;int main(int argc, char *argv[])
{Cube c1;c1.set_h(10);c1.set_l(1);c1.set_w(2);c1.mj();c1.tj();return 0;
}

cube.cpp 文件

#include "cude.h"
#include <iostream>
using namespace std;
int Cube::get_l()
{return l;
}
int Cube::get_w()
{return w;
}
int Cube::get_h()
{return h;
}void Cube::set_l(int length)
{l = length;
}void Cube::set_w(int width)
{w = width;
}
void Cube::set_h(int height)
{h = height;
}void Cube::mj()
{int x = 2 * l * w + 2 * l * h + 2 * w * h;cout << "立方体面积为:" << x << endl;
}
void Cube::tj()
{int x = l * w * h;cout << "立方体体积为:" << x << endl;
}

cube.h 文件

#ifndef CUDE_H
#define CUDE_H
class Cube
{
private:int l;int w;int h;
public:int get_l();int get_w();int get_h();void set_l(int length);void set_w(int width);void set_h(int height);void mj();void tj();
};
#endif // CUDE_H

5. 构造函数

5.1 概述

构造函数:类实例化对象的时候自动调用。

注意:

  • 当一个类中 没有构造函数系统将默认 为其 生成一个无参构造
  • 如果一个类中有构造函数,系统将不会为其提供默认的无参构造
  • 一个类 可以 定义多个 构造函数,该类中的 多个构造函数为重载关系

无参构造:

  • 构造函数无形参列表

有参构造:

  • 构造函数有形参列表

5.2 语法

类名(形参列表)
{ 该类对象赋初始值
} 注意:形参列表可有可无

5.3 示例

#include <iostream>using namespace std;
class A{
private:int a;
public:A(){cout << "无参构造被调用了" << endl;}A(int x){cout << "有参构造被调用了" << endl;}void test(){cout << "test" << endl;}
};int main(int argc, char *argv[])
{//隐式调用无参构造//类名 对象名A a1;//显式调用无参构造//类名 对象名 = 构造函数名();A a2 = A();//隐式调用有参构造A a3(10);//显式调用有参构造A a4 = A(20);//隐式转换(了解)//当调用的构造函数中只有一个参数时可用A a5 = 10;cout << "********************" << endl;//匿名对象//没有对象名的对象// 注意:一个匿名对象只能使用一次A().test();A(1000).test();return 0;
}
//无参构造被调用了
//无参构造被调用了
//有参构造被调用了
//有参构造被调用了
//有参构造被调用了
//********************
//无参构造被调用了
//test
//有参构造被调用了
//test

6. 析构函数

6.1 概述

对象生命周期结束的时候,自动调用析构函数。

注意:

  • 一个类 只能有 一个析构函数
  • 如果 用户不提供 析构函数 编译器 默认会提供一个空的析构函数

经验:

  • 一般不需要 自定义析构函数,但是如果类中有指针成员且指向堆区空间,这时 必须实现析构函数,在其中释放指针成员指向的堆区空间

6.2 语法

~类名()
{}

注意:没有形参列表

6.3 示例

#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Data{
private:int a;int b;char *msg;
public:Data(){msg = NULL;}Data(int x, int y){a = x;b = y;msg = NULL;}Data(int x, int y, char *m){a = x;b = y;msg = (char *)malloc(50);strcpy(msg, m);}~Data(){cout << "析构函数被调用了" << endl;//判断msg堆区空间是否被释放if(msg != NULL){free(msg);msg = NULL;}}
};void fun01()
{Data d1;
}
int main(int argc, char *argv[])
{//fun01();    //析构函数被调用了  对象生命周期结束自动触发析构函数Data d2;    //析构函数被调用了 打开下面的死循环,不会被调用
//    while(1);return 0;
}

7. 多对象构造与析构顺序

7.1 对象A与对象B平级,符合栈的顺序(先进后出),谁先创建谁后释放

#include <iostream>using namespace std;
class A{
private:int a;
public:A(){cout << "A无参构造函数被调用了" << endl;}A(int x){a = x;cout << a << "构造函数被调用了" << endl;}~A(){cout << a << "析构函数被调用了" << endl;}
};void fun01()
{A a1(1);A a2(2);{A a3(3);A a4(4);}
}int main(int argc, char *argv[])
{fun01();return 0;
}

结果:

1构造函数被调用了
2构造函数被调用了
3构造函数被调用了
4构造函数被调用了
4析构函数被调用了
3析构函数被调用了
2析构函数被调用了
1析构函数被调用了

7.2 对象A是对象B的成员,先成员构造,再对象构造,再对象析构,再成员析构

#include <iostream>using namespace std;
class A{
private:int a;
public:A(){cout << "A无参构造函数被调用了" << endl;}A(int x){a = x;cout << a << "构造函数被调用了" << endl;}~A(){cout << a << "析构函数被调用了" << endl;}
};void fun01()
{A a1(1);A a2(2);{A a3(3);A a4(4);}
}class B{
private:int b;A a;
public:B(int x){b = x;cout << b << "B的构造函数被调用了" << endl;}~B(){cout << b << "B的析构函数被调用了" << endl;}
};
void fun02()
{B b(5);
}int main(int argc, char *argv[])
{//fun01();fun02();return 0;
}
//A无参构造函数被调用了
//5B的构造函数被调用了
//5B的析构函数被调用了
//4200699构造函数被调用了

8. 拷贝构造函数

8.1 概述

拷贝构造在以下情况自动触发:

  1. 旧对象给新对象初始化,会调用拷贝构造函数
  2. 对象作为函数的形参,函数调用时会调用拷贝构造
  3. 普通对象作为函数的返回值(vsCode会触发拷贝构造,Qt、Linux不会触发拷贝构造)

注意:

  • 如果 用户不提供拷贝构造 编译器会提供一个默认 的拷贝构造(浅拷贝)

  • 只有 类中有指针成员且指向堆区时 才有必要实现拷贝构造(深拷贝)。

浅拷贝与深拷贝:

  • 浅拷贝:当类中的成员有指针成员,此时只拷贝地址
  • 深拷贝:当类中的成员有指针成员,先开辟内存,再拷贝其值

8.2 语法

类名(const 类名 &ob)
{ }

8.3 示例

#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Stu{
public:int x;
public:Stu(){cout << "Stu无参" << endl;}Stu(int a){x = a;cout << "Stu有参" << endl;}/*拷贝构造语法:类名(const 类名& 对象名){函数体}拷贝构造调用情况:1,使用老对象初始化新对象2,调用的函数时,该函数的形参为对象3,函数的返回值是对象*/Stu(const Stu& s){cout << "拷贝构造被调用了" << endl;x = s.x;}
};void fun01()
{Stu s1(10);//将老对象初始化新对象,会触发拷贝构造Stu s2 = s1;cout << "s1.x = " << s1.x << endl;cout << "s2.x = " << s2.x << endl;s2.x = 100;cout << "s1.x = " << s1.x << endl;cout << "s2.x = " << s2.x << endl;
}void test01(Stu s)
{}
void fun02()
{Stu s;test01(s);
}Stu test02()
{static Stu s;return s;
}
void fun03()
{Stu s = test02();
}int main(int argc, char *argv[])
{fun01();	//情况1fun02();	//情况2cout << "--------------" << endl;fun03();	//情况3return 0;
}//Stu有参
//拷贝构造被调用了
//s1.x = 10
//s2.x = 10
//s1.x = 10
//s2.x = 100//Stu无参
//拷贝构造被调用了
//--------------
//Stu无参
//拷贝构造被调用了

8.4 示例:浅拷贝

注意:

  • 在释放内存时,先释放p2 ,其指向的地址会被释放,但是p1的地址还是0x01,再次释放就会报错,所以浅拷贝会存在问题
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Person{
private:int age;char *name;
public:Person(int a, char *n){age = a;name = (char *)malloc(50);strcpy(name, n);}//浅拷贝//系统提供的拷贝构造就是浅拷贝//只拷贝地址,不拷贝值Person(const Person& p){name = p.name;age = p.age;}void set_name(char *na){strcpy(name, na);}void print_info(){cout << "姓名:" << name << "\t年龄:" << age << endl;}~Person(){if(name != NULL){free(name);name = NULL;}}
};int main(int argc, char *argv[])
{Person p1 = Person(18, "张三");Person p2 = p1;p1.print_info();    //姓名:张三	年龄:18p2.print_info();    //姓名:张三	年龄:18p2.set_name("李四");p1.print_info();    //姓名:李四	年龄:18p2.print_info();    //姓名:李四	年龄:18return 0;
}

在这里插入图片描述

8.5 示例:深拷贝

深拷贝会在堆区再开辟一块内存,将值拷贝到这块内存,即p1和 p2指向了不同的内存空间,释放时是各自释放各自的,不会存在问题

#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Person{
private:int age;char *name;
public:Person(int a, char *n){age = a;name = (char *)malloc(50);strcpy(name, n);}//深拷贝Person(const Person& p){age = p.age;name = (char *)calloc(1,50);strcpy(name, p.name);}void set_name(char *na){strcpy(name, na);}void print_info(){cout << "姓名:" << name << "\t年龄:" << age << endl;}~Person(){if(name != NULL){free(name);name = NULL;}}
};int main(int argc, char *argv[])
{Person p1 = Person(18, "张三");Person p2 = p1;p1.print_info();    //姓名:张三	年龄:18p2.print_info();    //姓名:张三	年龄:18p2.set_name("李四");p1.print_info();    //姓名:张三	年龄:18p2.print_info();    //姓名:李四	年龄:18return 0;
}

9. 初始化列表

9.1 概述

构造函数:主要用于创建类的对象是给其属性赋初始值

在定义构造函数时,c++中提供了初始化列表的语法,以便于初始化成员变量的值。

9.2 语法

类名(参数列表):成员名(参数名),成员名2(参数名2),... {
}

9.3 示例

#include <iostream>using namespace std;
class A{
private:int a,b;
public:A(){}
//    A(int x,int y)
//    {
//        a = x;
//        b = y;
//    }A(int x,int y):a(x),b(y){}A(const A& obj){a = obj.a;b = obj.b;}~A(){}void print_info(){cout << a << "\t" << b << endl;}
};class B{
public:int c;A a;
public:B(int z,int x,int y):c(z),a(A(x,y)){}
};
int main(int argc, char *argv[])
{A a(1,7);   //1	7a.print_info();B b(1,2,3);cout << b.c << endl; //1b.a.print_info();    //2 3return 0;
}

10. explicit关键字

作用:禁止隐式转换

语法:

explicit 类名(形参列表):初始化列表
{}

示例:

class C{
private:int a;
public:explicit C(int x):a(x){}
};
int main(int argc, char *argv[])
{ C c = 10;//构造函数的隐式转换//当调用构造函数使用explicit修饰后防止隐式转换,此时上述代码报错return 0;
}

11. new / delete

  • 当用 new 创建一个对象时,它就 在堆里为对象分配内存并调用构造函数完成初始化;

  • new 表达式的反面是 delete 表达式。 delete 表达式先调用析构函数,然后释放内存。正如 new 表达式返回一个指向对象的指针一样, delete 需要一个对象的地址。delete 只适用于由 new 创建的对象。

11.1 情况1:操作基本类型

作用:

  • new:申请堆区空间;
  • delete:释放堆区空间。

示例:

#include <iostream>using namespace std;void fun01()
{int *p1 = new int;*p1 = 100;cout << *p1 << endl;    //100int *p2 = new int(200); //给p2的值初始化为200cout << *p2 << endl;    //200delete p1;delete p2;
}int main(int argc, char *argv[])
{fun01();return 0;
}

11.2 情况2:操作数组

作用:

  • new:申请堆区空间;
  • delete:释放堆区空间。

示例:

#include <iostream>
using namespace std;
void fun02()
{//int nums01[5] = {0};int *nums01 = new int[5];//int nums02[5] = {1,2,3,4,5};int *nums02 = new int[5]{1,2,3,4,5};for(int i = 0; i < 5; i++){cout << nums01[i] << endl;}cout << "------------------" << endl;for(int i = 0; i < 5; i++){cout << nums02[i] << endl;}//delete nums01;//只会释放数组中第一个元素的内存delete [] nums01;delete [] nums02;
}int main(int argc, char *argv[])
{fun02();return 0;
}
//7798976
//7798976
//0
//0
//-150994442
//------------------
//1
//2
//3
//4
//5

11.3 情况3:操作对象

作用:

  • new:分配空间,调用构造函数 ;
  • delete:调用析构函数,释放空间 。

示例:

#include <iostream>using namespace std;class A{
public:A(){cout << "A无参" << endl;}~A(){cout << "A析构" << endl;}
};
int main(int argc, char *argv[])
{//不会调用构造函数
//    A *a = (A *)calloc(1,sizeof(A));//不会调用析构函数
//    free(a);//会调用构造函数A *a1 = new A();//会调用析构函数delete a1;
//    while(1);return 0;
}

12. 对象数组

数组中存放的是对象。

对象数组:必须 显示 调用构造函数初始化

12.1 静态对象数组

示例:

#include <iostream>using namespace std;
class A{
public:int mA;
public:A(){cout<<"A无参构造"<<endl;}A(int a){mA = a;cout<<"A有参构造mA="<<mA<<endl;}~A(){cout<<"A析构函数mA="<<mA<<endl;}
};
void fun04()
{//对象数组 必须显示调用构造函数初始化A arr[5]={A(10),A(20),A(30),A(40),A(50)};int n = sizeof(arr)/sizeof(arr[0]);int i=0;for(i=0;i<n;i++){cout<<arr[i].mA<<" ";}cout<<endl;
}int main(int argc, char *argv[])
{fun04();return 0;
}
//A有参构造mA=10
//A有参构造mA=20
//A有参构造mA=30
//A有参构造mA=40
//A有参构造mA=50
//10 20 30 40 50 
//A析构函数mA=50
//A析构函数mA=40
//A析构函数mA=30
//A析构函数mA=20
//A析构函数mA=10

12.2 动态对象数组

示例:

void fun05()
{ A *arr = new A[5]{A(10),A(20),A(30),A(40),A(50)};int i=0;for(i=0;i<5;i++){cout<<arr[i].mA<<" ";} cout<<endl;//delete arr;//只会释放第0个元素delete [] arr;
}//A有参构造mA=10
//A有参构造mA=20
//A有参构造mA=30
//A有参构造mA=40
//A有参构造mA=50
//10 20 30 40 50 
//A析构函数mA=50
//A析构函数mA=40
//A析构函数mA=30
//A析构函数mA=20
//A析构函数mA=10

13. 静态成员

static 修饰的成员为静态成员。

建议使用 类名 调用静态成员

  • 静态成员在类加载之初被加载,不占用对象的空间
  • 非静态成员加载在对象中
  • 成员函数加载到代码区

13.1 静态成员变量

13.1.1 概述

特点:

  • 静态成员是 属于类 而不是对象。(所有对象共享)

注意:

  • 静态成员数据 不占对象的内存空间
  • 静态成员数据是属于类 而不是对象(多个对象共享一份静态成员数据)
  • 静态成员数据 在 定义对象之前 就存在。静态成员数据在类中定义,类外初始化。
13.1.2 示例
#include <iostream>
using namespace std;
class A{
public:static int num;int num03;
public:A(){}
};
//类外初始化
int A::num = 10;
int main(int argc, char *argv[])
{A a1 = A();a1.num03 = 20;cout << sizeof(a1) << endl;  //4cout << a1.num << endl;      //10//对象a1.num03赋值cout << "a1.num03 = " << a1.num03 << endl;//a1.num03 = 20A a2;//对象a2.num03没有赋值,所以是随机值cout << "a2.num03 = " << a2.num03 << endl;//a2.num03 = 6422384cout << "a1.num = " << a1.num << endl;//a1.num = 10cout << "a2.num = " << a2.num << endl;//a2.num = 10//通过a2修改num的值,a1.num也随之改变a2.num = 100;cout << "a1.num = " << a1.num << endl;//a1.num = 100cout << "a2.num = " << a2.num << endl;//a2.num = 100return 0;
}
13.1.3 小结
1,属于类的,不属于对象,当前类中所有对象共有一份,不占用对象的内存空间
2,可以使用类名直接调用,也可以使用对象名调用类名调用:类名::静态成员变量名对象调用:对象名.静态成员变量名
3,在类中定义,在类外初始化,初始化时不关注访问权限修饰符,在类外使用时关注访问权限修饰符

13.2 静态成员函数

使用 static 修饰的成员函数

特点:

  • 静态成员函数中 只能使用静态成员

示例

#include <iostream>
#include "cstring"
using namespace std;
class Stu{
private:static char c[50];char name[50];int age;
public://有参构造函数,方便对象初始化Stu(char n[50],int a){strcpy(name,n);age = a;}void print_info(){cout << name << endl;cout << age << endl;cout << c << endl;}//注意静态成员函数中只能使用静态成员static void test(){//cout << name << endl; //报错//cout << age << endl;cout << c << endl;}
};
//当静态为私有的
//此时可以对其进行初始化,但是不能直接使用
char Stu::c[50] = "iot2302";int main(int argc, char *argv[])
{//隐式调用有参构造Stu s01("张三",23);Stu s02("李四",24);Stu s03("王五",23);s01.print_info();s02.print_info();s03.print_info();//使用对象名调用静态成员(public权限下)//strcpy(s01.c,"iot2303");//建议使用类名调用静态成员(public权限下)//cout << Stu::c << endl;s01.print_info();s02.print_info();s03.print_info();//静态成员函数,可以使用类名调用,也可以使用对象名调用s01.test();Stu::test();return 0;
}//张三
//23
//iot2302
//李四
//24
//iot2302
//王五
//23
//iot2302//张三
//23
//iot2302
//李四
//24
//iot2302
//王五
//23
//iot2302//iot2302
//iot2302

14. 单例模式

设计模式:

每一个设计模式是为了解决 一种特点的问题

概述:所属的类 只能实例化一个对象。

思想:

  • 私有化构造函数
  • 提供公共函数,返回该类对象

14.1 饿汉式:返回创建好的对象

缺点:占用内存多

优点:线程安全

示例:

#include <iostream>using namespace std;
class A{
private:int x;//实例化A的对象,此时是个指针static A *a;
private:A(){}A(const A& a){}
public://普通函数在外部只能通过对象调用,这个类在外部没法创建对象,//所以只能创建为公共静态函数,在外部通过类调用。//这个函数是为了返回该类的对象,如果只返回A,还是会触发拷贝构造(旧对象给新对象初始化),//因为拷贝构造函数已经私有化,所以只能返回类的引用static A& getInstance(){//返回该类的对象(对a取值,就是对象)return *a;}
};
// 静态成员变量 类外初始化,开辟内存,所以是地址,用指针接收 
A *A::a = new A();
void fun01()
{//返回的是A的引用个,所以接收的也是A的引用这种类型A& a1 = A::getInstance();A& a2 = A::getInstance();A& a3 = A::getInstance();//打印这3个对象的地址,相同说明实例化的是同一个对象cout << &a1 << endl; //0x1e7030cout << &a2 << endl; //0x1e7030cout << &a3 << endl; //0x1e7030
}int main(int argc, char *argv[])
{fun01();return 0;
}

14.2 懒汉式:第一次调用时创建对象并返回,后面调用返回第一次创建的对象

缺点:线程不安全

优点:占内存少

示例:

class B{
private:int x;static B* b;
private:B(){}B(const B& b){}
public:static B& getInstance(){//判断是否已经创建对象if(b == NULL){b = new B();}return *b;}
};
B *B::b = NULL;
int main(int argc, char *argv[])
{B& b1 = B::getInstance();B& b2 = B::getInstance();B& b3 = B::getInstance();cout << &b1 << endl; //0xf37040cout << &b2 << endl; //0xf37040cout << &b3 << endl; //0xf37040return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Electron自定义通知Notification

Notification是什么&#xff1f; 对于渲染进程&#xff0c;Electron 允许开发者使用通知中API&#xff0c;来运行系统的原生通知进行显示。 如何实现系统Notification&#xff1f; const { Notification } require(electron);const isAllowed Notification.isSupported();…

AI 引擎系列 8 - 运行时比率参数简介

简介 在 Versal AI 引擎 2 一文 中&#xff0c;我们注意到计算图 (graph) 文件中有一行内容用于为每个内核实例定义运行时比率参数。 在本文中&#xff0c;我们将讲解该参数如何影响 AI 引擎应用的资源使用率和性能。 要求 下文要求您通读前几篇 AI 引擎系列博文。 AI 引擎系…

cesium实现区域贴图及加载多个gif动图

1、cesium加载多个gif动图 Cesium的Billboard支持单帧纹理贴图&#xff0c;如果能够将gif动图进行解析&#xff0c;获得时间序列对应的每帧图片&#xff0c;然后按照时间序列动态更新Billboard的纹理&#xff0c;即可实现动图纹理效果。为此也找到了相对于好一点的第三方库libg…

亚线性空间算法1

流模型 问题&#xff1a;如果采用bit存储的话 可以是n或者是Logn 但是对于特别大的数据量 这也是不行的&#xff0c;所以我们思考是否有Loglogn的算法 来存储统计的数据。 问题1&#xff1a;近似计数Morris算法 多次实验 使结果更准确。 问题2&#xff1a;不重复元素/FM算法…

3分钟了解安全数据交换系统有什么用!

企业为了保护核心数据安全&#xff0c;都会采取一些措施&#xff0c;比如做网络隔离划分&#xff0c;分成了不同的安全级别网络&#xff0c;或者安全域&#xff0c;接下来就是需要建设跨网络、跨安全域的安全数据交换系统&#xff0c;将安全保障与数据交换功能有机整合在一起&a…

acwing linux docker教程

终章 听着名字还挺伤感的哈哈哈其实是Linux的终章&#xff0c;感谢大家这段时间的阅读&#xff0c;这段使时间我为了给大家清楚的讲解一下Linux自己也是很认真的学习了一遍&#xff0c;自己提升了也不少。其实最近学校里面是讲了Linux和windows server 2019搭载DNS、web、ftp服…

HarmonyOS 组件隔代双向数据通信Provide与Consume

今天 我们说一个场景 我们可以编写代码如下 Entry Component struct Index {State name:string "小猫猫";build() {Row() {Column() {Text(this.name)Button("改个name").onClick(() > {this.name this.name "小猫猫"?"小狗狗&quo…

论文阅读——X-Decoder

Generalized Decoding for Pixel, Image, and Language Towards a Generalized Multi-Modal Foundation Model 1、概述 X-Decoder没有为视觉和VL任务开发统一的接口&#xff0c;而是建立了一个通用的解码范式&#xff0c;该范式可以通过采用共同的&#xff08;例如语义&#…

VScode远程连接服务器,Pycharm专业版下载及远程连接(深度学习远程篇)

Visual Code、PyCharm专业版&#xff0c;本地和远程交互。 远程连接需要用到SSH协议的技术&#xff0c;常用的代码编辑器vscode 和 pycharm都有此类功能。社区版的pycharm是免费的&#xff0c;但是社区版不支持ssh连接服务器&#xff0c;只有专业版才可以&#xff0c;需要破解…

web架构师编辑器内容-HTML2Canvas 截图的原理

HTML2Canvas 截图的原理 目的&#xff1a;一个canvas元素&#xff0c;上面有绘制一系列的HTML节点 局限&#xff1a;canvas中没法添加具体的Html节点&#xff0c;它只是一张画布 通过canvas.getContext(‘2d’)可以拿到canvas提供的2D渲染上下文&#xff0c;然后在里面绘制形…

【Hive】——函数案例

1 Hive 多字节分隔符处理 1.1 默认规则 Hive默认序列化类是LazySimpleSerDe&#xff0c;其只支持使用单字节分隔符&#xff08;char&#xff09;来加载文本数据&#xff0c;例如逗号、制表符、空格等等&#xff0c;默认的分隔符为”\001”。根据不同文件的不同分隔符&#xf…

Git一个仓库包含多个不同的项目VUE(老项目的基础上,新建分支放新项目)

背景&#xff1a; 原有项目A&#xff08;vue2.6&#xff09;&#xff0c;需要在A的基础上接入组件库&#xff0c;涉及到项目升级&#xff0c;领导不想走这条路&#xff0c;建议重新构建一版2.7的项目B&#xff0c;那么现在就需要把项目B与项目A远程到同一个仓库&#xff1b; 解…