C++面向对象编程(上)

news2024/11/15 10:52:42

类与对象属于面向对象的程序设计思想(Object Oriented Programming),简称OOP。

面向对象基础理论

面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物,是一种软件开发的方法

面向对象四大特性

1.抽象

忽略一个主题中与当前目标无关的东西,专注的注意与当前目标有关的方面。就是把现实世界中的某一类东西提取出来,用程序代码表示,抽象出来的一般叫做类或者接口。抽象并不打算了解全部问题,而是选择其中一部分,暂时不考虑部分细节。抽象包括两个方面,一个是数据抽象,一个是过程抽象。

数据抽象:表示世界中一类事物的特征,就是对象的属性。比如鸟有翅膀、羽毛等(类的属性

过程抽象:表示世界中一类事物的行为,就是对象的行为。比如鸟会飞(类的方法

2.封装

封装是面向对象的特征之一,是对象和类概念的主要特征。封装就是把过程和数据包围起来,对数据的访问只能通过已定义的界面。如私有变量,用set和get方法获取。

封装保证了模块具有较好的独立性,使得程序维护修改较为容易。对应用程序的修改仅限于类的内部,因而可以将应用程序修改带来的影响减少到最低程度。

3.继承

一种联结类的层次模型,并且允许和鼓励类的重用,提供一种明确表达共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特称,新类称为派生类(子类),原始类被称为新类的基类(父类)。派生类的可以从它的父类那里修改或增加新的方法,使之更适合特殊的需要。因此可以说,继承不仅能重用父类代码,同时为实现多态性作了准备。

继承的原则:继承使得一个对象可以获取另一个对象的属性。使用继承可以让已经测试完备的功能得到复用。并且可以一次修改,所有继承的地方都同时生效。

4.多态

多态是指允许不同类的对象对同一消息做出响应。多态性包括参数化多态性和包含多态性。多态性语言具有灵活/抽象/行为共享/代码共享的优势,很好的解决了应用程序函数同名的问题(函数重载,方法重写,方法的动态链接)。

动态链接:对于父类中定义的方法,如果子类中重写了该方法,那么父类类型的引用将调用子类中的这个方法,这就是动态链接。

访问权限修饰符

定义时的修饰符

此处修饰符多指访问修饰符,在C++中共有三种访问修饰符:

public:公共的。可以被任何类访问。可通过对象访问

private:私有的。只能被同一类内的方法访问,其它任何类(包括子类)都无法访问。也可以被友元函数访问。不可通过对象访问。

protected:受保护的。可以被同一类访问,也可以被子类访问。不可由其他类访问。不可由对象访问。

继承时的修饰符

public:使用public继承,父类的方法属性不会发生改变

private:使用private继承,父类的所有方法在子类中变为private,不允许子类使用。

protected:使用protected继承,父类的protected和public方法在子类变为protected,private方法不变。

初识:类与对象

类和对象概述

类(Class):具有相同特征的事物的抽象描述,是抽象的、概念上的定义。即:具有相同属于与行为的一系列事物的统称。例如:人类,动物类,车类等

对象(Object):实际存在的该类事物的每个个体,是具体的,因而也被称为实例具有具体属性和行为的每一个事物都可称之为对象。(万物皆可对象)

成员变量(field)

语法格式:

[修饰符] class 类名{
    [修饰符] 数据类型 成员变量名[=初始化值];//属性
}

成员函数(member function) 

[修饰符] class 类名{
    [修饰符] 返回值类型 成员函数(参数列表){
        函数体;
    }//方法
}

接口与抽象类 

认识:抽象类与接口

一、抽象类 

抽象类是特殊的类,只能被继承,无法实例化;除此以外,抽象类具有类的全部特征;重要的是抽象类可以包含抽象方法,而普通类不能声明或定义抽象的方法。

抽象方法:不包含任何实现,由派生的子类完成内部方法体内容(必须实现覆盖)

注意:抽象类可以派生一个抽象子类。抽象子类可以覆盖基类的抽象方法也可以不覆盖,如果不覆盖,则该派生类的派生类必须覆盖它们。

二、接口

接口是引用类型的,类似于“类”,和抽象类的相似之处:

1.无法实例化

2.包含未实现的方法声明

3.派生类必须实现未实现的方法,抽象类是抽象方法,接口则是所有的成员(不仅是方法,还包括其他成员)

接口的特性:接口除了可以包含方法以外,还可以包含属性、索引器、事件等,而且这些成员都被定义为公有的(public)。除此以外,不能包含任何其它成员,例如常量、域、构造函数、析构函数、静态成员。

Tips:“一个类可以直接继承多个接口,但只能直接继承一个类(包括抽象类)”

区别:抽象类与接口

1.抽象类是对类的抽象,(类是对对象的抽象),可以把抽象类理解为对象为类的类。而接口只是一个行为的规范或规定,微软的自定义接口总是后带able字段,证明其是表述一类类“我能做......”。抽象类更多的是定义在一系列紧密关系的类之间,而接口大多是关系疏松但都实现某一功能的类中。

2.接口不具有继承的任何特点,它仅仅承诺了能够调用的方法。

3.一个类一次能实现若干个接口,只能拓展一个父类,却可以同时拓展多个接口。

4.接口可以用于支持回调,而继承不具备这个特点

5.抽象类不能被密封。

6.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法默认为非虚的,当然也可以显式声明为虚的。

7.接口与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。

8.抽象类实现了oop中的一个原则,把可变与不可变进行分离。抽象类和接口就是定义为不可变的,而把可变的作为子类去实现。

9.好的接口定义应该具有专一功能性的,而不是多功能的,否则会造成接口污染。

接口污染:如果一个类只是实现了这个接口中的一个功能,而不得不额外实现接口的其它方法,这个现象就是接口污染。

10.如果用抽象类实现接口,则可以把接口中的方法映射到抽象类中作为抽象方法而不必实现,但需要在抽象类的子类中实现接口中的方法

11.尽量避免使用继承来实现组件功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把它们全部加载到栈中,后果可想而知。同时,有心的朋友可以留意到微软在构建一个类时,很多时候用到了对象组合的方法。比如:asp.net中的Page类,有Server Request等属性,但其实它们都是某个类的对象。使用Page类的这个对象来调用另外的类的方法和属性,这个是非常基本的一个涉及原则。(其实在这里,我个人觉得合适的例子就是:优先级队列类priority_queue的底层实现可以是vector类,这个就是用vector类的一些方法来构建priority_queue类的一些功能)

对象的初始化与清理

1.构造函数

主要作用是在创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。

语法:类名(){}

class A{
    A(){
        //没有返回值,不写void
        //函数名称与类名相同
        //构造函数可以有参数,因此可以进行重载
        //程序在调用对象时自动调用构造函数,无序手动调用,而且只调用一次
        //当构造函数发生重载时,编译器根据参数列表自动匹配构造函数
        //不写构造函数时,该类默认构造函数即:A(){}
    }
};

 预备知识:new运算符的基本使用,方法重载:C++函数重载-CSDN博客

class Pointer {
private:
	int* p = nullptr;
	int size = 0;
public:
	Pointer() { cout << "无参构造" << endl; }
	Pointer(int num) {
		cout << "有参构造" << endl;
		if (num <= 0)return;
		size = num;
		p = new int[num];
	}
	Pointer(int* x)
		:p(x)
		,size(size+1)
	{cout << *p << endl ;}
};
int main() {
	int x = 3;
	Pointer p1;//无参构造
	Pointer p2(10);//有参构造-1
	Pointer p3(&x);//有参构造-2
	return 0;
}

在上述代码中,我们创建了三个Pointer类 类型的变量,创建时,p1无参数传入,采用无参构造;p2传入要开辟的堆区空间数量为10,那么 通过new运算符开辟10个空间,空间大小size更新为10;p3通过初始化列表进行初始化。

初始化列表:以冒号开始,逗号分隔,括号中给值

//写法1.
Pointer(int x):p(x),size(1){
    
}
//写法2.
Pointer(int x)
    :p(x)
    ,size(1)
{}

注意:

1.只能在构造函数中使用

2.初始化顺序和成员变量定义顺序一致

3.常量和引用要在初始化列表中初始化 

初始化顺序与初始化列表顺序无关:

class A {
	int a, b, c;
public:
	A(int a, int b, int c) 
		:a(a)
		,b(b)
		,c(c) 
	{cout << a << " " << b << " " << c << endl;}

	A(int b1,int c1)
		:c(c1)
		,a(c)
		,b(b1)
	{cout << a << " " << b << " " << c << endl;}

	
};
int main() {
	A a(1, 2, 3);

	A aa(1, 2);
	return 0;
}

oi!,结果有点不如人意哦,怎么会出现了-858993460呢?这就是我们所说的初始化顺序与初始化列表顺序无关,初始化顺序与成员变量定义时的顺序有关:首先给a初始化,赋值时是c的值,c没有初始化,采用随机值;然后给b初始化b1:1;然后给c初始化c1:2。最后我们的结果就是 随机 1 2;并不是2 1 2。 

构造函数调用方式

1.括号法:上述都是用括号法写的 

Pointer p(3);

2.显式法:像函数的使用一样

Pointer p = Pointer(3);

3.隐式转换法:使用等号=

Pointer p = 3;
//在此次,会调用参数为int类型的构造函数,将3 转化为Pointer类型的对象

 注意:Pointer p();这种写法并不是括号调用无参构造,它会被编译器识别为函数声明,返回值为Pointer ,参数列表为空,函数名为p的一个函数。

构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

1.默认构造函数(无参,函数体为空)

2.默认析构函数(无参,函数体为空)

3.默认拷贝构造函数:对属性进行值拷贝

调用的具体规则:如果用户定义有参构造函数,c++不再提供默认无参构造函数,但会提供默认拷贝构造函数。如果用户定义拷贝构造函数,c++不会提供其它构造函数。

构造函数习后练习

练习一:创建一个矩形类,属性包括长宽,通过构造函数初始化举行对象,打印矩形的面积。通过三种方式分别调用构造函数。

class Rectangle{
    int width;
    int length;
public:
    Rectangle()
        :width(0)
        ,length(0)
    {}
    Rectangle(int width,int length){
        this->width=width;
        this->length=length;
    }
    void Print_S()
    {cout<<width*length<<endl;}
};

int main()
{
    //无参构造
    Rectangle r;
    r.Print_S();

    //括号法
    Rectangle r1(1,2);
    r1.Print_S();
    
    //隐式法
    Rectangle r2 = {1,2};
    r2.Print_S();

    //显式法
    Rectangle r3 = Rectangle(1,2);
    r3.Print_S();

    return 0;
}

练习二:创建一个person类,其中属性包括:姓名,性别,年龄,循环输入3个人并且打印出每个人的信息 。

class Person{
    string name;
    string sex;
    int age;
public:
    Person(string name,string sex,int age){
        this->name=name;
        this->sex=sex;
        this->age=age;
    }
    void showInfo(){
        cout<<"姓名:"<<name<<endl;
        cout<<"性别:"<<sex <<endl;
        cout<<"年龄:"<<age <<endl;
    }
};

int main()
{
    vector<Person> vec={Person("张三","男",18),Person("小丽","女",1),Person("李四","男",0)};
    for(auto e:vec){
        e.showInfo();
    }

    Person* per = new Person("张三","男",11);
    delete per;

    Person* pers=new Person[3]{Person("张三","男",18),Person("小丽","女",1),Person("李四","男",0)};
    for(int i=0;i<3;i++){
        pers[i].showInfo();
    }
    delete[] pers;
    return 0;
}
2.析构函数

主要作用是在对象销毁前系统自动调用,执行一些清理工作

语法:~类名(){}

class A{
    ~A(){
        //析构函数,没有返回值也不写void
        //函数名称和类名相同,在名称前符号 ~ 
        //析构函数不可以有参数,因此不可以发生重载
        //程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
    }
};
class Pointer{
    int* p;
public:
    Pointer()
        :p(nullptr)
    {}
    Pointer(int num){
        p=new int(num);
    }

    ~Pointer(){
        if(p) delete p;
    }
};
int main()
{
    Pointer p1(3);//栈区
    //new 会先调用malloc分配足够的内存,再掉用构造函数给分配的内存赋值
    Pointer *p2=new Pointer(3);
    delete p2;
    //delete 先调用析构函数,再调用free释放内存
    
    //new 和 malloc区别?
    return 0;    
}
3.this指针

一个对象的this指针并不是对象本身的一部分,不影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员时,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。

this是指向当前对象的指针,哪个对象调用包含this指针的函数,this指向哪个对象。

this一般在构造函数中使用,用于区分成员变量和参数。

class A{
public:
    int num;
    /*
        this,是成员函数的隐含参数,当对象调用成员函数时,会将对象的地址赋值给this指针
        this 的作用?
        1.使用this区分成员变量和形参
        2.在函数内区分不同对象的成员变量
    */
    void set_num(int num){
        this->num=num;
    }
};
 4.拷贝构造函数

C++中拷贝构造函数调用时机通常有三种情况:

1.使用一个已经创建完毕的对象来初始化一个新对象(直接调用)

2.值传递的方式给函数参数传值(实参初始化形参)

3.以值的方式返回局部对象

注意:参数或者返回值为引用类型时,可以避免调用拷贝构造

拷贝构造:通过当前的对象复制出一份一摸一样的对象

class A{
private:
    int num;
public:
    A():num(0){//无参构造
    }
    A(int a){//有参构造
        num=a;
    }
    A(const A& other){//拷贝构造
        num=other.num;
    }
}
void test01(){
    A a;//无参构造
    A b = a;//隐式调用拷贝构造
    A c(a);//用已经存在的对象初始化新的对象
    A d= A(a);//显式调用拷贝构造
}
void test02(A a){
    //类类型做参数
}
A test03(){
    A a;
    return a;
}
int main(){
    //test01();

    //A p;test02(p);

    A a = test03();//用来接收
    return 0;
}

 

对于拷贝构造, 参数必须为引用,不然就会陷入无限递归,递归就是函数自己调用自己。

在这里我们无法验证递归的现象

VS2022:(直接报错)

DevC++ :(直接优化为const A&)

*深拷贝与浅拷贝

深浅拷贝是面试经典问题,也是常见的一个坑。

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作。

#include <bits/stdc++.h>
using namespace std;
#define Long long long

class A{
	int* p;
	int num;
public:
	A() {//无参构造
		this->num = 0;
		p = nullptr;
	}
	A(int a) {//有参构造
		this->num = a;
		p = new int[num];
		for (int i = 0; i < num; i++) {
			p[i] = 0;
		}
	}
	A(const A& other) {//拷贝构造
		/*
		* 浅拷贝:简单的赋值操作,保证值相等
		* 浅拷贝问题:
		*		如果有指针指向堆区内存时,不同对象的指针成员指向同一堆区内存
		*		在对象释放时,该堆区内存会被释放两次,当一个对象修改堆区内存时,另一个对象也会随着变化
		* p=other.p;
		* this->num=other.num;
		*/

		//深拷贝:申请相同大小的堆区空间,保证两个对象的堆区值相同
		num = other.num;
		p = new int[num];
		for (int i = 0; i < num; i++) {
			p[i] = other.p[i];
		}
	}
};
int main() {
	A a(5);//有参构造
	A b(a);//深拷贝

	//A o;//无参构造
    A o(1);
	A c(o);//浅拷贝
	return 0;
}

 深拷贝内存地址:

浅拷贝内存地址:

总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的多对象共享同一造成的内存问题。

类对象作为类成员

在本目录中“接口与抽象类”的区别版块,第11条就提到了类对象作为类的成员的情况。这十分常用。

C++类中的成员可以是另一个类的对象,我们称成员为对象成员

例如:

class A{};

class B{
    A member-a;
};

 B类中有对象A作为成员,A作为对象成员。

那么当创建B时,A与B的构造和析构的顺序是谁先谁后呢?

class B{
public:
    B(){
        cout<<"构造B"<<endl;
    }
    ~B(){
        cout<<"析构B"<<endk;
    }
}
class A{
    B b;
public:
    A(){cout<<"构造A"<<endl;}
    ~A(){cout<<"析构A"<<endl;}
}

int main(){
    //创建对象a时,先创建成员变量b(B构造),再调用A的构造函数给成员变量赋值
    A a;
    return 0;
}

 

静态成员(static)

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员

静态成员分为:静态成员变量,静态成员函数

1.静态成员变量

1.所有对象共享一份数据

2.编译阶段分配内存,在主函数前进行构造

3.类内声明,类外初始化

4.在发生继承时,静态成员变量不会被继承,父类子类共享一个静态成员

5.可以使用类或对象访问公有的静态成员变量

6.静态成员变量不占对象的内存(不计入sizeof(对象)的结果)

 

这里C++sizeof的用法支持sizeof直接加需要计算的类型或数据,更符合sizeof的本质--运算符的写法,而不是c语言的函数风格

tips:空类的大小为1。

2.静态成员函数

1.静态成员函数只能访问静态成员变量

2.没有this指针,所以静态成员函数内部不可以使用非静态的成员变量和成员函数

空指针访问成员函数

C++中空指针也是可以调用成员函数的,但是也要注意有没有用到this指针。如果用到this指针,需要加以判断保证代码的健壮性。

class Person{
    int num;
public :
    void work(){
        cout<<"work"<<endl;
    }
    void fun(){
        num=2;
    }
};

int main(){
    Person* p=nullptr;
    p->work();//bingo正确,输出work
    p->fun();//error,错误。通过指针来调用成员函数时,就是把p的值给成员函数的this,现在p为空,那么在函数体访问this->num时就会出错
    return 0;
}

const修饰成员函数

本节知识比较重要,之后会单写一篇博客(知识点补充专栏)进行讲解,后续会把链接加到这块。

友元

友元的目的是让一个函数或者类,访问另一个类中私有的成员。

友元的关键字为friend 是一个修饰符

友元分为友元类和友元函数

1.全局函数做友元

2.类做友元

好处:可以通过友元在类外访问类内的私有和受保护类型的成员

坏处:破坏了类的封装性

class A {
	int num_a;
public:
	friend void fun();
	friend class B;

	A() { cout << "构造-A" << endl; }
	~A() { cout << "析构-A" << endl; }
};
A a;
void fun() {
	a.num_a = 2;
	cout << a.num_a << endl;
}
class B {
public:
	void fun() {
		a.num_a = 2;
	}
	B() { cout << "构造-B" << endl; }
	~B() { cout << "析构-B" << endl; }
};
int main() {
	fun();
	return 0;
}

不辞辛苦,码了近万字,初步介绍认识C++中的面向对象编程知识,希望点赞+收藏走一波,之后可能还会在本节进行后续的修改补充等。感谢大家!

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

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

相关文章

数据库(五):多表设计和多表查询

项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在各种联系&#xff0c;基本上分为三种&#xff1a;一对一、多对一、一对多…

如何在寂静中用电脑找回失踪的手机?远程控制了解一下

经过一番努力&#xff0c;我终于成功地将孩子哄睡了。夜深人静&#xff0c;好不容易有了一点自己的时间&#xff0c;就想刷手机放松放松&#xff0c;顺便看看有没有重要信息。但刚才专心哄孩子去了&#xff0c;一时就忘记哄孩子之前&#xff0c;顺手把手机放哪里去了。 但找过手…

进程相关知识

进程和程序的区别 程序 程序是静态的&#xff0c;是存储在硬盘、SSD等存储介质中的一个文件&#xff0c;通常由源代码&#xff08;如 .c 文件&#xff09;编译生成的二进制可执行文件&#xff08;如 a.out&#xff09;。程序包含了指令和数据&#xff0c;但在未被执行时&#…

【计算机操作系统】基本分页存储管理

文章目录 基本分页存储管理分页存储的概念重要的数据结构——页表页表项大小计算地址转换实现 基本地址变换机构具有快表的地址变换机构快表&#xff08;TLB&#xff09;的概念引入快表后的地址变换局部性原理 两级页表单级页表 vs 两级页表 基本分页存储管理 非连续分配&#…

使用Python编写AI程序,让机器变得更智能

人工智能&#xff08;AI&#xff09;是当今科技领域最热门的话题之一。随着Python编程语言的逐渐流行&#xff0c;它已经成为许多人工智能编程的首选语言。本文将介绍如何使用Python编写AI程序&#xff0c;让机器变得更智能。 首先&#xff0c;Python提供了大量的AI库和工具&a…

Easysearch 性能测试方法概要

&#xff08;公众号用的是QQ音乐&#xff0c;可以随时听&#xff09; INFINI Easysearch INFINI Easysearch 是一个分布式的近实时搜索与分析引擎&#xff0c;核心引擎基于开源的 Apache Lucene。Easysearch 衍生自基于开源协议Apache 2.0 的Elasticsearch 7.10 版本&#xff0…

4-1-2 直流电机(电机专项教程)

4-1-2 直流电机&#xff08;电机专项教程&#xff09; 4-1-2 直流电机主要参数尺寸参数额定电压额定电流空载转速 如何控制直流电机有刷直流电机转向控制H桥电路控制转向 如何控制电机转速PWM控制电机转速 4-1-2 直流电机 之前学习了有刷直流电机的基本结构个工作原理&#xff…

[数据集][图像分类]电力场景电力线固定处连接处腐蚀有鸟巢分类数据集1279张3类别

数据集类型&#xff1a;图像分类用&#xff0c;不可用于目标检测无标注文件 数据集格式&#xff1a;仅仅包含jpg图片&#xff0c;每个类别文件夹下面存放着对应图片 图片数量(jpg文件个数)&#xff1a;1279 分类类别数&#xff1a;3 类别名称:["corrosion","nes…

SparkSQL遵循ANSI标准

ANSI简介 ANSI Compliance通常指的是遵循美国国家标准学会&#xff08;American National Standards Institute, ANSI&#xff09;制定的标准。在计算机科学和技术领域&#xff0c;这通常涉及到数据库管理系统&#xff08;DBMS&#xff09;对于SQL语言的支持程度。 ANSI为SQL…

FreeRTOS 快速入门(二)之内存管理

目录 一、概述二、FreeRTOS 中管理内存的 5 种方法1、Heap_12、Heap_23、Heap_34、Heap_44.1 内存申请4.2 内存释放 5、Heap_5 三、Heap 相关的函数1、pvPortMalloc/vPortFree2、xPortGetFreeHeapSize3、xPortGetMinimumEverFreeHeapSize4、malloc 失败的钩子函数 一、概述 在…

CDGA|数据治理,就像在厨房里炒一盘好菜

数据治理&#xff0c;就像在厨房里炒一盘好菜&#xff0c;是一门既讲究技巧又注重细节的艺术。在这个信息爆炸的时代&#xff0c;数据如同食材&#xff0c;是支撑企业决策、优化运营、驱动创新的基石。而数据治理&#xff0c;则是将这些纷繁复杂的数据“食材”精心挑选、清洗、…

使用NPS搭建socks5隧道 | 内网穿透

在看春秋云镜靶场的WP时碰到用NPS来做代理的&#xff0c;这里刚好看到这篇文章&#xff1a;https://www.cnblogs.com/cute-puli/p/15508251.html&#xff0c;学习一下。 GUI界面管理更加方便。 实验环境 网络拓扑&#xff1a; kali&#xff1a; VMnet1&#xff08;公网&…

ORB-SLAM3演示及运行

ORB-SLAM安装完成后的运行案例 ros启动 1、修改双目部分文件&#xff0c;主要是图象订阅话题名称 因为我是用的双目灰度相机&#xff0c;需要修改ORB_SLAM3/Examples/ROS/ORB_SLAM3/src下的 ros_stereo.cc和 ros_stereo_intertial.cc. 把订阅的话题改为自己系统发布的图象…

盲盒小程序开发,创新市场收益渠道

对于年轻消费者来说&#xff0c;盲盒是一个具有超强惊喜感和刺激性的消费方式&#xff0c;盲盒也在各大社交平台迅速火爆&#xff0c;线下门店更是上演“大长龙”式的排队景观&#xff0c;盲盒成为了一个具有非常大发展前景的行业&#xff01; 一、线上发展 盲盒的销售渠道除…

矩阵和神经网络的优雅与力量-《Python神经网络编程》读后感

《Python神经网络编程》是一本非常优秀的神经网络入门编程书&#xff0c;作者手把手从安装环境开始&#xff0c;每一行代码都是在树莓派上就能运行的&#xff0c;甚至可以说不需要什么第三方库&#xff0c;仅仅用了矩阵的优雅和力量&#xff0c;就能够在树莓派上顺利的运行。 …

并发编程 | CountDownLatch是如何控制线程执行流程

CountDownLatch 是 Java 并发编程中的一个同步工具类&#xff0c;这个工具经常用来用来协调多个线程之间的同步&#xff0c;下面我们就来一起认识一下 CountDownLatch。 CountDownLatch介绍 应用场景 CountDownLatch主要是用于让一个或多个线程等待其他线程完成某些操作后再…

鸿蒙Harmony实战开发知识:“UIAbility组件的3种启动模式”

UIAbility的启动模式是指UIAbility实例在启动时的不同呈现状态。针对不同的业务场景&#xff0c;系统提供了三种启动模式&#xff1a; singleton启动模式 singleton启动模式为单实例模式&#xff0c;也是默认情况下的启动模式。 每次调用startAbility()方法时&#xff0c;如…

windows下的redis7.0.11的下载

天&#xff0c;我找redis7.0.11的安装包就找了好久&#xff0c;终于给我找到了。市面上好多是linux版本的。 安装包&#xff1a;Release Redis 7.0.11 for Windows zkteco-home/redis-windows GitHub 解压之后是这样的。 然后你要测试能不能启动&#xff1a; 1、指定配置文…

复现DOM型XSS攻击(1-8关)

目录 第一关&#xff1a;​ 分析代码&#xff1a; 第二关&#xff1a; 分析代码&#xff1a; 第三关&#xff1a; 分析代码&#xff1a; 第四关&#xff1a; 分析代码&#xff1a; 第五关&#xff1a; 分析代码&#xff1a; 第六关&#xff1a; 分析代码&#xff1…

volatitle-线程并发-小白一文速通

目录 简而言之 专业术语解释 1、可见性 原理简介 原理图解 其他方式 2、原子性 原理简介 结合实例分析 3、有序性 原理简介 线程安全问题 Volatile效果 1、保证可见性 2、保证有序性 3、无法保证原子性 Volatile底层的实现机制(重点掌握) 经典案例 Java双重检…