13. C++类使用方式

news2025/1/25 9:05:18


【类】

C语言使用函数将程序代码模块化,C++通过类将代码进一步模块化,类用于将实现一种功能的全局数据、以及操作这些数据的函数集中存储在一起,同时可以设置类成员的访问权限,禁止外部代码使用和篡改本类成员,类成员访问限制的功能由编译器提供,对程序进行逆向分析并修改时并不存在这些限制。

为了区分类成员与类外的全局数据、全局函数,类中的数据称为成员数据、类中的函数称为成员函数。

类的使用方式类似结构体,也是先声明再使用,类的实例称为对象,对象有类型之分,通过哪个声明定义的对象就属于哪个类型。

声明类时需要设置类成员访问权限,限制成员使用范围,类成员有三种访问权限:
1.private,私有成员,只有本类可以使用,外部代码、子类、内部类都不能使用。
2.protected,保护成员,本类和本类的子类可以使用。
3.public,公有成员,可以被任何外部代码使用。

多个类成员可以分别设置为不同的访问权限,编写代码时,类对外提供的功能定义为公有成员,不对外提供的功能定义为私有成员,若类成员未设置访问权限,则默认为私有成员,私有成员不能在类外部直接调用,但是可以被本类的公有成员在外部调用,从而让公有成员执行本类实现的功能。

类可以看做是结构体的扩充版,类可以存储函数,并为内部成员设置访问权限,实际上C++的结构体也可以当做类使用,在结构体内存储函数,结构体与类的唯一区别是成员默认访问权限不同,类成员默认为私有权限,结构体成员默认为公有权限,为了区分类与结构体,一般不会使用结构体代替类,结构体只用于将一些全局数据、成员数据分类存储。

#include <iostream>

/* 使用class声明类 */
class zoo
{
    
/* 公有成员 */
public:
    char name[50];
    int age;
    
    void output()
    {
        printf("姓名:%s\n年龄:%d岁\n\n", name, age);
    }
};    //以;符号结尾

int main()
{
    zoo ali = {"阿狸", 8};    //创建类对象并为成员数据赋值,若类中定义了私有成员数据则不能在创建对象时直接赋值
    ali.output();            //调用成员函数执行
    
    return 0;
}

对象本质

创建多个同类型对象时,这些对象只是成员数据的值不同,成员函数完全相同,这些对象完全没必要各自建立一份自用的成员函数,实际上编译器会对代码进行简化,让多个同类型对象共用一份成员函数。

#include <iostream>
class zoo
{
public:
    char name[50];
    int age;
    void output()
    {
        printf("姓名:%s\n年龄:%d岁\n\n", name, age);
    }
};
int main()
{
    zoo ali = {"阿狸", 8};
    ali.output();
    
    zoo xyy = {"喜羊羊", 9};
    xyy.output();
    
    return 0;
}

上述C++代码等同于如下C语言代码:

#include <stdio.h>
struct zoo
{
    char name[50];
    int age;
};
void output(struct zoo * this)
{
    printf("姓名:%s\n年龄:%d岁\n\n", this->name, this->age);
}
int main()
{
    struct zoo ali = {"阿狸", 8};
    output(&ali);
    
    struct zoo xyy = {"喜羊羊", 9};
    output(&xyy);
    
    return 0;
}

创建对象时,编译器会将对象中的成员数据定义为一个结构体实例,多个对象共用一份成员函数,每个成员函数自动添加一个名为this的指针参数,this指向要操作的结构体实例,既然this指针是实际存在的参数,那当然可以直接使用它,比如下面的代码:

#include <iostream>
class zoo
{
public:
    char name[50];
    int age;
    void output()
    {
        printf("姓名:%s\n年龄:%d岁\n\n", this->name, this->age);    //使用this指针参数调用成员数据
    }
};
int main()
{
    zoo ali = {"阿狸", 8};
    ali.output();
    
    zoo xyy = {"喜羊羊", 9};
    xyy.output();
    
    return 0;
}

成员函数与对象的关系

在语法上,创建对象时包含成员函数,可以通过对象调用成员函数执行。
在功能上,成员函数独立于对象,成员函数通过this指针参数调用操作的对象。

对象使用方式

类对象会被编译为结构体实例,结构体实例的使用方式都可以转移到类对象中。
1.同类型的对象之间可以赋值。
2.对象可以作为函数参数和返回值。
3.类可以嵌套定义。

对象指针

对象指针使用方式类似结构体指针,使用对象指针调用内部成员时,只有成员数据使用指针调用,成员函数会转换为直接调用,原因是所有同类型对象共用一组成员函数,编译器通过“对象指针类型+函数名”即可确定要调用的函数,无需使用间接寻址。

#include <iostream>
class zoo
{
public:
    char name[50];
    int age;
    void output()
    {
        printf("姓名:%s\n年龄:%d岁\n\n", name, age);
    }
};
int main()
{
    zoo ali = {"阿狸", 8};
    zoo *p1 = &ali;
    p1->output();
    
    return 0;
}

上述C++代码相当于如下C语言代码:

#include <stdio.h>
struct zoo
{
    char name[50];
    int age;
};
void put(struct zoo * this)
{
    printf("姓名:%s\n年龄:%d岁\n\n", this->name, this->age);
}
int main()
{
    struct zoo ali = {"阿狸", 8};
    struct zoo *p1 = &ali;
    
    output(p1);    //直接调用函数,而非通过函数指针
    
    return 0;
}

构造函数与析构函数

构造函数和析构函数是编译器自动调用的成员函数,创建对象时自动执行构造函数,对象不再使用后自动执行析构函数。

构造函数

构造函数与类同名,可以在构造函数内定义创建对象后需要首先执行的一些代码,比如为对象赋值、申请内存、打开文件,当然也可以使用普通成员函数完成相关工作,但是普通成员函数需要手动调用,若忘记调用则可能出错。

构造函数使用特点如下:
1.构造函数可以没有,此时创建对象时编译器不会调用构造函数执行。
2.构造函数必须定义为公有权限,否则无法在外部执行。
3.可以有参数,此时需要在创建对象时为构造函数参数赋值,若无参数则完全由编译器自行管理。
4.不能有返回值,因为构造函数由编译器自动调用,无法接收返回值,若需与其他函数通信可以使用成员变量、全局变量实现。
5.可以被重载,编译器根据使用的参数确定调用的重载构造函数。
6.构造函数为对象成员数据赋值时,成员数据默认值不生效(成员数据默认值在之后讲解)。
7.若定义了构造函数,则不能在定义对象时直接为对象赋值,这种限制是为了防止直接赋值与构造函数赋值产生冲突。

#include <iostream>
#include <string.h>
class zoo
{
public:
	char name[50];
	int age;
	void output()
	{
		printf("姓名:%s\n年龄:%d岁\n\n", name, age);
	}
	
	/* 构造函数 */
	zoo()
	{
		name[0] = 0;
		age = 0;
	}
	
	/* 重载构造函数 */
	zoo(const char *s, const int i)
	{
		strncpy(name, s, 49);
		age = i;
	}
};
int main()
{
	zoo x;        //调用无参数构造函数
	x.output();
	
	zoo ali("阿狸", 8);    //调用两个参数的构造函数
	ali.output();
	
	zoo xyy = {"喜羊羊", 9};    //这种语法表示为构造函数参数赋值,而不是直接为对象赋值,{}符号内的数据对应构造函数参数,而非成员数据
	xyy.output();
	
	return 0;
}

析构函数

析构函数会在对象使用完毕后自动执行,可以在析构函数内定义一些函数执行完毕后需要执行的代码,比如释放内存、关闭文件,析构函数也是与类同名,但是需要前缀~符号与构造函数区分。

析构函数执行条件如下:
1.创建此对象的函数执行完毕。
2.对象使用new申请内存存储,之后调用delete释放了内存。

析构函数使用特点如下:
1.析构函数可以没有,此时编译器不会调用析构函数执行。
2.必须定义为公有权限,否则无法在外部执行。
3.没有参数,也没有返回值,若需与其它函数通信可以使用全局变量实现。

#include <iostream>
#include <string.h>
class zoo
{
public:
	char name[50];
	int age;
	
	/* 构造函数 */
	zoo(const char *s, const int i)
	{
		strncpy(name, s, 49);
		age = i;
		
		printf("zoo构造函数执行\n");
	}
	
	/* 析构函数 */
	~zoo()
	{
		printf("zoo析构函数执行\n");
	}
};
int main()
{
	zoo ali("阿狸", 8);
	printf("main函数执行完毕\n");
	
	return 0;
}

编译以上代码并执行,观察构造函数、析构函数的执行顺序。

嵌套类

嵌套定义的类称为内部类,内部类将会当做所属类的成员使用,多数情况下内部类设置为私有权限,不对外开放,只供所属类的其它成员使用。

#include <iostream>
class zoo
{
private:
    class fox
    {
    public:
        char name[50];
        int age;
        void output()
        {
            printf("姓名:%s\n年龄:%d岁\n\n", name, age);
        }
    };
    
public:
    fox ali = {"阿狸", 8};
    fox taozi = {"桃子", 7};
    
    void attr()
    {
        ali.output();
        taozi.output();
    }
};
int main()
{
    zoo zoo1;
    zoo1.attr();
    
    return 0;
}

类中定义本类对象

可以在本类中定义本类的对象,但是只能定义在成员函数内,因为成员函数本质上是独立于类的,若定义为成员数据将会产生无限循环嵌套,导致语法错误。

#include <iostream>
class zoo
{
public:
    char name[50];
    int age;
    void f1()
    {
        zoo ali = {"阿狸", 8};
        printf("姓名:%s\n年龄:%d岁\n\n", ali.name, ali.age);
    }
};
int main()
{
    zoo zoo1;
    zoo1.f1();
    
    return 0;
}

使用new申请对象内存

不带构造函数

#include <iostream>
#include <string.h>
class zoo
{
public:
	char name[50];
	int age;
	void output()
	{
		printf("姓名:%s\n年龄:%d岁\n\n", name, age);
	}
	
	~zoo()
	{
		printf("zoo析构函数执行\n");
	}
};
int main()
{
	zoo * p1 = new zoo;
	strncpy(&p1->name[0], "阿狸", 49);
	p1->age = 8;
	p1->output();
	
	delete p1;          //使用delete释放内存后会自动调用对象析构函数
	
	printf("main函数执行完毕\n");
	
	return 0;
}

带构造函数

#include <iostream>
#include <string.h>
class zoo
{
public:
	char name[50];
	int age;
	void output()
	{
		printf("姓名:%s\n年龄:%d岁\n\n", name, age);
	}
	
	zoo()
	{
		name[0] = 0;
		age = 0;
	}
	zoo(const char *s, const int i)
	{
		strncpy(name, s, 49);
		age = i;
	}
};
int main()
{
	zoo * p1 = new zoo();    //调用无参数构造函数
	p1->output();
	delete p1;
	
	zoo * p2 = new zoo("阿狸", 8);    //调用有参数构造函数
	p2->output();
	delete p2;
	
	return 0;
}

友元

类成员如果不考虑继承关系,只有公有、私有两种访问权限,要么禁止所有外部代码访问,要么允许所有外部代码访问,这种权限设置不灵活,所以C++增加了友元功能,友元是为某个外部代码单独设置的访问权限,可以让指定的类、成员函数、全局函数访问本类的私有成员。

友元最常用于内部类,将本类的内部类定义为友元,之后内部类就可以使用所属类的私有成员。

友元使用特点如下:
1.友元关系不会被继承。
2.友元关系是单向的,若需使用双向友元则需要在两个类中同时设置对方为自己的友元。
3.在友元中创建本类对象时不能直接赋值,可以使用构造函数赋值。

友元类

#include <iostream>
#include <string.h>
class zoo
{
	/* 使用friend关键词设置k类为友元 */
	friend class k;
	
private:
	char name[50];
	int age;
	void output()
	{
		printf("姓名:%s\n年龄:%d岁\n", name, age);
	}
	
	zoo(const char *s, const int i)
	{
		strncpy(name, s, 49);
		age = i;
	}
};
class k
{
public:
	void f1()
	{
		zoo ali("阿狸", 8);
		ali.output();
	}
};
int main()
{
	k k1;
	k1.f1();
	
	return 0;
}

友元成员函数

可以单独设置某个类的成员函数为友元,但是此函数必须在类外定义内容,并且有固定的定义顺序,顺序如下:
1.定义友元成员函数所属类。
2.定义需要设置友元关系的类。
3.在类外部定义友元成员函数的内容代码。

#include <iostream>
#include <string.h>

/* 定义友元成员函数所属类 */
class k
{
public:
	void f1();    //只定义友元成员函数主体部分,不定义内容
};

/* 定义设置友元的类 */
class zoo
{
	friend void k::f1();    //设置友元成员函数,若函数有参数则需要同时指定参数类型和名称
	
private:
	char name[50];
	int age;
	void output()
	{
		printf("姓名:%s\n年龄:%d岁\n", name, age);
	}
	
	zoo(const char *s, const int i)
	{
		strncpy(name, s, 49);
		age = i;
	}
};

/* 定义友元成员函数内容 */
void k::f1()
{
	zoo ali("阿狸", 8);
	ali.output();
}

int main()
{
	k k1;
	k1.f1();
	
	return 0;
}

友元全局函数

#include <iostream>
#include <string.h>
class zoo
{
	friend int main();    //设置main为友元
	
private:
	char name[50];
	int age;
	void output()
	{
		printf("姓名:%s\n年龄:%d岁\n", name, age);
	}
	
	zoo(const char *s, const int i)
	{
		strncpy(name, s, 49);
		age = i;
	}
};
int main()
{
	zoo ali("阿狸", 8);
	ali.output();
	
	return 0;
}


【成员数据使用细节】

成员数据默认值

声明成员数据时可以设置默认值,公有成员、私有成员都可以设置默认值,创建对象时若不赋值则编译器使用默认值自动赋值,若构造函数也会为对象赋值,则以构造函数为准。

#include <iostream>
class math
{
public:
    int a=0, b=0;    //设置默认值
    void add()
    {
        printf("a+b=%d\n", a+b);
    }
};
int main()
{
    math math1;           //使用默认值
    math1.add();          //输出0
    
    math math2 = {1,2};   //自行赋值
    math2.add();          //输出3
    
    return 0;
}

常量成员数据

若成员数据定义为常量,则需要在创建对象时直接赋值,之后不能修改,只能读取它的值,若不为常量成员数据赋值则必须设置默认值。

注意不能使用构造函数为常量成员数据赋值,因为对象的创建早于构造函数的执行,此时等于使用构造函数修改常量成员数据,将会禁止编译。

私有成员数据

类成员应该尽量定义为私有的,不需要被外部代码调用的成员都应该设置为私有权限,防止被类外代码调用、修改导致出错,因为类成员不能在类外直接调用,所以类中包含私有成员数据时创建本类对象不能直接赋值,私有成员数据可以使用如下方式赋值:

1.设置默认值。
2.使用构造函数赋值。
3.使用其他公有函数赋值。

#include <iostream>
class math
{
private:
	int a,b;
	
public:
	void add()
	{
		printf("a+b=%d\n", a+b);
	}
	void mul()
	{
		printf("a*b=%d\n", a*b);
	}
	
	math(int i1, int i2)
	{
		a = i1;
		b = i2;
	}
};
int main()
{
	math math1(1,2);
	math1.add();
	math1.mul();
	
	return 0;
}


【成员函数使用细节】

成员函数在类外部定义内容

成员函数内容代码可以放在所属类外部定义,类中只定义成员函数的主体,这样方便阅读类实现的整体功能。

#include <iostream>
class math
{
private:
	int a,b;
	
public:
	void add();    //类中定义函数主体部分,若有参数则需要同时定义参数
	void mul();
	
	math(int i1, int i2)
	{
		a = i1;
		b = i2;
	}
};

/* 类外定义成员函数内容,因为不同类的成员可以同名,所以这里需要指定函数所属的类 */
void math::add()
{
	printf("a+b=%d\n", a+b);
}
void math::mul()
{
	printf("a*b=%d\n", a*b);
}

int main()
{
	math math1(1,2);
	math1.add();
	math1.mul();
	
	return 0; 
}

常量成员函数

常量成员函数是只读取成员数据、不修改成员数据的成员函数,而且它只能调用其他常量成员函数执行,不能调用非常量成员函数,这是为了防止通过调用非常量成员函数间接修改成员数据。

常量成员函数主要作用是服务于常量对象,对象可以定义为常量,防止被修改,常量对象中的成员函数只有常量成员函数可以执行,原因同上,类中不修改成员数据的函数都应该定义为常量成员函数,这样不仅可以被常量对象调用、还可以防止编写代码时不小心错误的修改了成员数据。

注:常量对象可以使用构造函数赋值,这与在类中定义常量成员数据不同,编译器会首先执行构造函数然后限制常量对象被修改。

#include <iostream>
class math
{
public:
	int a,b;
	
	/* 定义常量成员函数,const关键词写在参数之后 */
	void add() const
	{
		printf("a+b=%d\n", a+b);
	}
	
	void mul() const
	{
		printf("a*b=%d\n", a*b);
	}
};
int main()
{
	const math math1 = {1,2};    //定义常量对象,只能调用常量成员函数执行
	math1.add();
	math1.mul();
	
	return 0; 
}

成员函数指针

本类内部使用成员函数指针

#include <iostream>
class math
{
private:
	int a,b;
	
public:
	math(int i1, int i2)
	{
		a = i1;
		b = i2;
	}
	
	int add() const
	{
		return a+b;
	}
	int mul() const
	{
		return a*b;
	}
	void output() const
	{
		int result;
		
		int(math::*p1)()const = &math::add;    //p1为指针名,const表示指向常量成员函数,赋值为add函数地址
		result = (this->*p1)();                //使用指针执行成员函数
		printf("a+b=%d\n", result);
		
		p1 = &math::mul;
		result = (this->*p1)();
		printf("a*b=%d\n", result);
	}
};
int main()
{
	math math1(1,2);
	math1.output();
	
	return 0;
}

使用成员函数指针注意事项如下:
1.定义成员函数指针时,需要指定指针所属类,此指针只能指向本类中的成员函数,包括继承自父类的函数。
2.成员函数指针赋值时,需要指定成员函数所属类,即使成员函数与成员函数指针就在同一个类中。
3.执行指针指向的函数时,需要使用this参数调用成员函数指针、然后通过成员函数指针调用指向的函数,编译器会使用本函数this参数为执行函数的this参数赋值。

本类外部使用成员函数指针

使用对象指针调用成员函数时会转换为直接寻址,成员函数并非通过指针调用,若有此需求可以在本类外部使用成员函数指针,成员函数在所属类之外通过指针调用时需要首先其所属类对象,并使用此对象的地址为成员函数的this参数赋值。

#include <iostream>
class math
{
private:
	int a, b;
	
public:
	math(int i1, int i2)
	{
		a = i1;
		b = i2;
	}
	
	void add() const
	{
		printf("a+b=%d\n", a+b);
	}
	void mul() const
	{
		printf("a*b=%d\n", a*b);
	}
};
int main()
{
	math math1(1,2);           //定义math对象
	
	void(math::*p1)()const;    //定义math类的成员函数指针
	
	p1 = &math::add;
	(math1.*p1)();      //通过指针执行函数,需要指定对象名,成员函数使用此对象为this参数赋值
	
	p1 = &math::mul;
	(math1.*p1)();
	
	return 0;
}


【静态类成员】

类成员可以定义为静态的,静态成员直接通过类名调用,创建对象时不会包含类静态成员,就像C语言中静态局部变量等于全局变量、不包含在函数中一样。

静态类成员的作用是将一些全局数据、全局函数放在类中管理,方便将全局代码进行分类。

静态成员数据特点如下:
1.不能设置默认值,因为此数据本质上不属于此类成员。
2.需要在类外定义一遍,否则禁止编译,可以同时设置初始值,类内只是声明此数据的所属权,而非定义此数据。

静态成员函数特点如下:
1.不能操作所属类的非静态成员,因为静态成员函数没有this指针参数。
2.可以调用所属类的其它静态成员。

#include <iostream>
class math
{
public:
    /* 静态成员数据 */
    static int a, b;
    
    /* 静态成员函数 */
    static void add()
    {
        printf("a+b=%d\n", a+b);
    }
};
int math::a = 0;    //静态成员数据在类外定义
int math::b = 0;
int main()
{
    math::a = 1;    //使用类名调用静态类成员,也可以使用对象名调用,调用的都是同一个数据
    math::b = 2;
    math::add();
    
    return 0;
}

上述C++代码等同于如下C语言代码:

#include <stdio.h>
int a=0, b=0;
void add()    //add函数没有this指针参数
{
    printf("a+b=%d\n", a+b);
}
int main()
{
    a = 1;
    b = 2;
    add();
    
    return 0;
}

静态类成员指针

静态类成员指针的定义方式与全局数据相同,只不过在赋值时需要额外指定数据所在类。

#include <iostream>
class math
{
public:
	static int a, b;
	static void add()
	{
		printf("a+b=%d\n", a+b);
	}
};
int math::a = 0;
int math::b = 0;
int main()
{
	int * p1 = &math::a;
	*p1 = 1;
	
	int * p2 = &math::b;
	*p2 = 2;
	
	void(*p3)() = &math::add;
	p3();
	
	return 0;
}


 

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

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

相关文章

Vue开发实例(六)实现左侧菜单导航

左侧菜单导航 一、一级菜单二、二级菜单三、三级菜单1、加入相关事件 四、菜单点击跳转1. 创建新页面2. 配置路由3. 菜单中加入路由配置4、处理默认的Main窗口为空的情况 五、动态左侧菜单导航1、动态实现一级菜单2、动态实现二级菜单 一、一级菜单 在之前的Aside.vue中去实现…

Dynamo初学尝试梳理(五)-代码块上

“学而时习之&#xff0c;不亦说乎”&#xff0c;今天接着来&#xff0c;稍微提高点难度&#xff08;高手直接忽略就行&#xff09;。 代码块&#xff08;Code Block&#xff09;&#xff0c;是 dynamo 中可以直接输入 DesignScript 的节点。可以通过双击鼠标左键&#xff0c;快…

JAVA WEB案例-登录校验-日志记录

一 前言 在现代社会中&#xff0c;随着互联网的快速发展&#xff0c;WEB应用的安全性问题变得越来越突出。作为一名程序员&#xff0c;我们不仅要注重WEB应用的功能实现&#xff0c;还需要重视安全性问题。在实际开发中&#xff0c;登录校验是非常重要的安全措施&#xff0c;能…

使用mapbox navigation搭建一个安卓导航 示例

一.代码示例地址&#xff1a; https://github.com/mapbox/mapbox-navigation-android-examples/tree/main 二. 具体步骤&#xff1a; git clone gitgithub.com:mapbox/mapbox-navigation-android-examples.git Go to app/src/main/res/values Look for mapbox_access_token.…

[R] Underline your idea with ggplot2

Preview: # 介绍&#xff1a;之前的教程中&#xff0c;我们学习了如何使条形图或直方图看起来更好 比如&#xff1a; 1. How to select a graph calibrate the geom part 2. How to select variables calibrate the aes part 3. How to add a title calibrate the labs …

Golang各版本的GC详解

go v1.3的标记清除法 清除的第一步&#xff1a;stw将可达对象标记删除未被标记对象 go v1.5三色标记法 从根节点出发&#xff0c;将下一个节点遍历为灰色&#xff0c;放入灰色集合中遍历灰色节点集合&#xff0c;把灰色能到达的节点标记为灰色&#xff0c;把自身标记为黑色&a…

安全增强型 Linux

书接上篇 一查看selinux状态 SELinux的状态&#xff1a; enforcing&#xff1a;强制&#xff0c;每个受限的进程都必然受限 permissive&#xff1a;允许&#xff0c;每个受限的进程违规操作不会被禁止&#xff0c;但会被记录于审计日志 disabled&#xff1a;禁用 相关命令…

SystemVerilog Support

介绍 AMD Vivado™合成支持可以合成的SystemVerilog RTL的子集。这个以下部分介绍了这些数据类型。 针对特定文件的SystemVerilog 默认情况下&#xff0c;Vivado合成工具使用Verilog 2005语法编译*.v文件和*.sv文件使用SystemVerilog语法。要在Vivado IDE中将SystemVerilog作…

**蓝桥OJ 178全球变暖 DFS

蓝桥OJ 178全球变暖 思路: 将每一座岛屿用一个颜色scc代替, 用dx[]和dy[]判断他的上下左右是否需要标记颜色,如果已经标记过颜色或者是海洋就跳过.后面的淹没,实际上就是哪个块上下左右有陆地,那么就不会被淹没,我用一个tag标记,如果上下左右一旦有海洋,tag就变为false.如果tag…

开发者如何选择代码签名证书?

代码签名证书是一种由权威认证机构颁发的数字证书&#xff0c;它允许软件开发者对其代码进行数字签名。这种签名基于公钥基础设施&#xff08;PKI&#xff09;技术&#xff0c;使用一对密钥&#xff1a;一个私钥和一个公钥。私钥用于生成签名&#xff0c;而公钥则嵌入到代码签名…

Linux学习-二级指针的使用

目录 ###指针传参时要用二级指针 ###函数体内部想要修改函数外部指针变量值的时候需要使用二级指针(指针变量的地址) ###指针传参时要用二级指针 char *str[5]; int Fun(char **ppstr,int len); ###函数体内部想要修改函数外部指针变量值的时候需要使用二级指针(指针变量的…

GCN原理回顾

Cora_dataset description Cora数据集是一个常用的学术文献用网络数据集&#xff0c;用于研究学术文献分类和图网络分析等任务。 该数据集由机器学习领域的博士论文摘要组成&#xff0c;共计2708篇论文&#xff0c;涵盖了7个不同的学科领域。每篇论文都有一个唯一的ID&#xf…

桥接模式: 消息发送器设计

桥接模式是一种结构型设计模式&#xff0c;它将抽象部分与它的实现部分分离&#xff0c;使它们可以独立地变化。桥接模式通过将抽象和实现分离&#xff0c;可以让它们可以独立地变化&#xff0c;从而提高系统的灵活性和可扩展性。 在桥接模式中&#xff0c;有两个重要的概念&a…

JavaBoy假期如何学习项目?弯道块才是真的快!

至暗时刻 老话说的好&#xff0c;弯道快才是真的快&#xff0c;谁直线不会加油&#xff1f;每到假期都是在座的各位弯道超车的时候。转眼自己已经出来搬了快四年砖头了&#xff0c;偶尔访问下牛客发现行情真是一年不如一年。。。不由得回想起自己春招时候的经历。 回想起2020年…

数据分析-Pandas数据的直方图探查

数据分析-Pandas数据的直方图探查 数据分析和处理中&#xff0c;难免会遇到各种数据&#xff0c;那么数据呈现怎样的规律呢&#xff1f;不管金融数据&#xff0c;风控数据&#xff0c;营销数据等等&#xff0c;莫不如此。如何通过图示展示数据的规律&#xff1f; 数据表&…

【贪心算法】Leetcode 455.分发饼干 376. 摆动序列 53. 最大子数组和

【贪心算法】Leetcode 455 分发饼干 376. 摆动序列【规律很多】53. 最大子数组和 455 分发饼干局部最优推全局最优&#xff1a;尽量用大饼干去满足大胃口的小朋友 376. 摆动序列【规律很多】思想&#xff1a;注意考虑一个坡度留首尾两个点、平坡、首尾 53. 最大子数组和【好思想…

FreeRTOS学习笔记-基于stm32(1)任务基础知识

一、裸机与RTOS 我们使用的32板子是裸机&#xff0c;又称前后台系统。裸机有如下缺点&#xff1a; 1、实时性差。只能一步一步执行任务&#xff0c;比如在一个while循环中&#xff0c;要想执行上一个任务&#xff0c;就必须把下面的任务执行完&#xff0c;循环一遍后才能执行…

从0开始学习NEON(2)

1、前言 继上一个例子&#xff0c;本次继续来学习NEON&#xff0c;本次学习NEON中向量拼接的操作&#xff0c;主要应用在图像的padding中。 https://blog.csdn.net/weixin_42108183/article/details/136440707 2、案例 2.1 案例1 在某些情况下&#xff0c;需要取在每个向量…

轻松压缩照片大小:简单实用的方法

当您需要通过网络传输或共享照片时&#xff0c;较小的文件大小可以提高传输速度并减少带宽消耗。这适用于通过电子邮件、社交媒体、即时消息应用程序等发送照片的场景。为了解决这个问题&#xff0c;本文将介绍一些简单而有效的方法来压缩照片的大小&#xff0c;以便更方便地分…

python并发编程:IO模型

一 IO模型 二 network IO 再说一下IO发生时涉及的对象和步骤。对于一个network IO \(这里我们以read举例\)&#xff0c;它会涉及到两个系统对象&#xff0c;一个是调用这个IO的process \(or thread\)&#xff0c;另一个就是系统内核\(kernel\)。当一个read操作发生时&#xff…