C++ | (二)类与对象(上)

燕子去了,有再来的时候;杨柳枯了,有再青的时候;桃花谢了,有再开的时候。但是,聪明的,你告诉我,我们的假期为什么一去不复返呢?

目录

一、初识类

1.1 类的定义

1.2 C++中的struct 

1.3 类的访问限定符

1.4 类域

1.5 对类的对象的成员的访问方式

 1.6 this指针

1.7 实例化与对象大小

二、再探类

2.1 类的默认成员函数

2.2 构造函数

2.3 析构函数 

2.4 拷贝构造函数 

2.5  运算符重载

2.6 赋值运算符重载 

2.7 const成员函数


一、初识类

1.1 类的定义

C++中,有一个特殊的关键字,叫作"",它源自于C语言的结构体,但比结构体要更加高级,比如,在C语言中的结构体内不能定义函数,而C++中的类却可以。

类的定义的关键字为“class”,类的内部包括成员函数成员变量,它的基本结构如下:

class class_name
{
public:void Fun1(){//...}//...
private:int _a;int _b;//...    
};

与C语言的结构体类似,类的“}”后也需要加“ ;”,否则编译器会报错。

PS:在上面的举例中,你一定会对“public”与“private”产生好奇,它们是什么含义我们稍后再说,但现在请你记住一点:成员函数一般放在public内,而成员变量一般放在private中。

1.2 C++中的struct 

在C++中,结构体struct升级为“类”,也就是说,C++中的struct内可以定义函数,可以进行一系列在class中进行的操作。

1.3 类的访问限定符

在类中储存的内容多种多样,既有公共安全的,也有私密不想被外界访问的,如何将在同一个类的它们区分开,使外部对它们有不同的访问权限呢?访问限定符可以很好的解决这个问题。

访问限定符共有三种:private、protected、public。使用方式是:访问限定符 + ' : '

访问限定符的作用域是从自己起到下一访问限定符的出现,或者是遇到class的' } '结束。

一般来说,在类中,我们会将成员函数放在public(公共的)中,将成员变量放在private/protected(私有的/受保护的)中。

例1: 

class Example
{
public:void fun1(){//...}int fun2(int a,int b){//...}
private:int _day;int _month;int _year;
};

这样做的结果就是,外界可以直接调用类里的成员函数,但无法直接访问类的成员变量,并对它进行修改。 

1.4 类域

类定义了一个新的作用域,类的所有成员都在类的作用域中,在类外定义类的成员时,需要使用类名+ ::  (作用域操作符)以指明所定义的成员属于哪个类域。

例2:

#include <iostream>
using namespace std;
class Example 
{
public:void fun1();void Print() {cout << _a <<"   " << _b << endl;}
private:int _a;int _b;
};
void Example::fun1() 
{_a = 1;_b = 1;
}
int main() 
{Example a;a.fun1();a.Print();return 0;
}

我们在类内对成员函数fun1进行了声明,但是在类外对成员函数fun1进行了定义,因而使用Example::对其加以限定。

1.5 对类的对象的成员的访问方式

与C语言中的结构体相同,有两种,一种是对象名 + ' . ' + 成员,一种是对象的地址 + ' -> ' + 成员

以例2中的对象a为例,想访问a中的fun1函数有两种形式:

	a.fun1();//1Example* pa = &a;pa->fun1();//2

 1.6 this指针

我们运行例2中的代码,运行结果为

这对于初学C++的人来说还是挺不可思议的,按照我们所学的C语言知识,fun1中的_a与_b应该与a中的_a与_b不是同一个变量,那么fun1对_a与_b修改就不会影响a中的成员变量_a与_b,但结果却是影响了,难道C++独树一帜,对C语言的语法进行大肆修改了?其实不然。

有上述疑问的人很正常,而有这样疑问的人恰恰证明你的C语言学的很扎实。

例2中的fun1与Print函数在编译器编译后的真正内容为:

void Example::fun1(Example* const this) 
{this->_a = 1;this->_b = 1;
}
void Print(Example* const this)
{cout << this->_a <<"   " << this->_b << endl;
}

也就是编译器之后给我们加上的内容。 

这样是不是就很熟悉了?这里的this指向的就是对象a。但是值得注意的是,在编译器中,不能在实参和形参的位置显示的写this指针,不要问为什么,这是规定。但是可以在函数体内显示使用this指针,所以上述内容应修改为:

void Example::fun1() 
{this->_a = 1;this->_b = 1;
}
void Print()
{cout << this->_a <<"   " << this->_b << endl;
}

这样编译就不会报错,且实现效果与例2一模一样。

我们从中也可以看出C++的优势,相对于C语言,C++省略了一些繁琐的地址传参,更加简洁。 

如果你充分了解了内部的机制,就不需要再在函数体内显示使用this指针,心里明白是为什么就可以了,该省劲的地方咱就省劲。

1.7 实例化与对象大小

用类类型在物理内存中创建对象的过程,称为 类实例化出对象。例如例2中类Example实例化出的对象a。类相当于工程图纸,而对象则是按照工程图纸建造出的建筑。

接着介绍如何对对象大小进行计算,首先,对象大小的计算仅包含其成员变量,因为成员函数在对象上的调用本质上是对该函数地址的调用,不需要每一个该类的对象都储存一个相同的函数,所以成员函数不占用对象所属的空间,而是存放在它处。至于成员变量,则是按照内存对齐规则进行计算,这里不再花费篇幅对内存对齐规则进行介绍,不懂的可以自行百度。

那么我们就可以计算得到例2中对象a的大小,为8字节。

到这里类的最基本的知识就介绍完毕了。

二、再探类

2.1 类的默认成员函数

什么是默认成员构造函数?默认成员构造函数就是用户没有显式实现,编译器自动生成的成员函数。一个类在未写成员函数的情况下编译器会自动生成六个默认成员函数,分别是构造函数,析构函数,拷贝构造函数,赋值重载函数,对普通对象取地址重载函数,对const对象取地址重载函数。最后两个函数很少会自己实现,所以我们先注重前四个默认成员函数,即构造函数、析构函数、拷贝构造函数、赋值重载函数。

默认成员函数的思维导图(取自比特就业课)

接下来让我们分别对其进行介绍。

2.2 构造函数

构造函数的作用是对象实例化时对对象进行初始化,它的出现是为了代替C语言中模拟实现像如Stack、Queue中写的Init函数的功能。构造函数自动调用的特点就可以作为Init函数的上位替代了。

接下来简单介绍构造函数的特点:

1. 函数名与类名相同

2. 无返回值,不写函数的返回值类型(void也不要写)

3. 对象实例化时系统会自动调用其对应的类中的构造函数。

4. 构造函数可以重载。

5. 若用户不显式定义构造函数,编译器会自动生成一个无参的默认构造函数;若用户显式定义构造函数,则编译器不会再生成默认的构造函数。

6. 编译器自动生成的构造函数对内置类型成员不做处理,对自定义类型成员会调用它所在类的构造函数

无参构造函数,全缺省构造函数,编译器默认生成的构造函数,均叫作默认构造函数(即不传实参就可调用的构造函数)

构造函数的使用举例:

#include <iostream>
using namespace std;
class Date 
{
public:Date() //无参构造函数,与全缺省构造函数只能存在一个{_day = 0;_month = 0;_year = 0;}Date(int year, int month, int day) //带参构造函数{_day = day;_month = month;_year = year;}void Print() {cout << _year << "/" << _month << "/" << _day << endl;}
private:int _day;int _month;int _year;
};
int main() 
{Date a;a.Print();Date b(2024, 9, 16);b.Print();return 0;
}

 代码运行结果:

注意:如果通过无参构造函数创建对象时,对象后不能跟括号,否则编译器无法区分是函数声明还是对象的实例化。

2.3 析构函数 

 析构函数的功能与构造函数相反,C++规定,对象在销毁时会自动调用析构函数,完成对象中资源的清理释放工作。析构函数的功能相当于C语言中Stack实现的Destroy功能,而部分对象的销毁没有资源需要释放,那么析构函数对于它们来说就是可有可无的。

析构函数的特点:

1. 函数名是在类名前加字符~

2. 无函数参数,无返回值,不需要写返回类型(void也不用)

3. 一个类仅能有一个析构函数。如果析构函数未被显式定义,编译器会自动生成默认的析构函数。

4. 对象的生命周期结束时,编译器会自动调用析构函数。

5. 编译器自动生成的析构函数对内置类型成员不做处理,对自定义类型成员会调用它所在类的析构函数。

6. 显式写析构函数,对于自定义类型成员也会调用它所在类的析构函数,即对于自定义类型成员,显式定义与编译器自动生成都会做出相同的处理:调用它所在类的析构函数。

7. 如果类中没有资源申请,析构函数可以不写,直接使用编译器生成的默认析构函数即可;如果有资源申请,一定要显式写析构函数(自己写),否则会造成资源泄露。

8. 一个局部域的多个对象,C++规定后定义的先析构。全局域的析构晚于局部域。

对于第八点的举例:

#include <iostream>
using namespace std;
class Exa 
{
public:Exa(char x='a') {_a = x;}~Exa() {cout <<"~Exa"<<_a<< endl;}
private:char _a;
};
Exa a('A');int main() 
{	Exa b('B');Exa c('C');return 0;
}
Exa d('D');

代码运行结果:

2.4 拷贝构造函数 

如果一个构造函数的第一个参数是对自身类的类型的引用,且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数。拷贝构造是一个特殊的构造函数。

拷贝构造函数的特点:

1. 拷贝构造函数是构造函数的一个重载。

2. C++规定自定义类型对象进行拷贝行为必须调用拷贝构造,所以自定义类型的传值传参和传值返回都会调用拷贝构造完成。

3. 拷贝构造函数的第一个参数必须是类类型对象的引用,使用传值方式编译器会报错,因为在语法逻辑上会引发无穷递归调用。(参照第二点)拷贝构造函数可以有多个参数,除第一个参数,后面的参数必须要有缺省值。

4. 若未显式定义拷贝构造,编译器会自动生成拷贝构造函数。自动生成的拷贝构造函数对内置类型成员变量会完成值拷贝/浅拷贝(一个字节一个字节的拷贝),对自定义类型成员变量会调用它所在类的拷贝构造函数。

5. 浅拷贝即可完成需求的类不需要写拷贝构造函数,而举例像如Stack(模拟实现栈的类)需要深拷贝,因为一个栈拷贝另一个栈不只有值拷贝,它的地址应不同于拷贝的栈,这时就需要深拷贝,即我们显式写类的拷贝构造函数,以完成深拷贝的需求。

6. 传值返回会产生一个临时对象调用拷贝构造,传值引用返回,返回的是返回对象的别名(引用),没有产生拷贝,但是如果返回对象是一个当前函数局部域的局部对象,函数结束时该对象就被销毁了,那么此时使用引用返回是有问题的,这时的引用相当于野引用。因此,传引用返回可以减少拷贝,但是一定要确保返回对象,在当前函数结束后未被销毁,才能返回引用,否则就返回值。

Ps 关于第三点中所提到的拷贝构造函数传值方式传参会引发无穷递归调用:

取自比特就业课

拷贝构造函数简单使用场景举例:

#include <iostream>
using namespace std;
class Stack
{
public:Stack(int x = 0,int y = 0,int z = 0) //默认构造函数{_capacity = 3;_top = 3;a = (int*)malloc(sizeof(int) * _capacity);a[0] = x;a[1] = y;a[2] = z;}Stack(const Stack& S) //拷贝构造函数{_capacity = S._capacity;_top = S._top;a = (int*)malloc(sizeof(int) * _capacity);a[0] = S.a[0];a[1] = S.a[1];a[2] = S.a[2];}void Print() {cout << a << endl;cout << a[0] << "  " << a[1] << "  " << a[2] << endl;}~Stack()//析构函数{free(a);}
private:int _capacity;int _top;int* a;
};int main() 
{	Stack s1(1, 2, 3);Stack s2;Stack s3(s1);s1.Print();s2.Print();s3.Print();return 0;
}

代码运行结果:

2.5  运算符重载

当运算符被用于类类型对象时,C++允许我们通过运算符重载的形式指定新的含义。C++规定类类型对象使用运算符时,必须调用对应的运算符重载,若没有对应的运算符重载,编译会报错。

运算符重载函数名由operator+运算符组成。运算符重载函数的参数个数和该运算符作用的运算对象数量一致。一元运算符有一个参数,二元运算符有两个参数,且二元运算符的左侧运算对象传给第一个参数,右侧运算对象传给第二个参数。(这一点非常重要,牢记哦)

如果一个运算符重载函数是类的成员函数,则它的第一个运算对象默认传给隐式的this指针,因此运算符重载作为成员函数时,参数比运算对象少一个。

运算符重载以后,其优先级和结合性与对应的内置类型运算符一致。

不能通过连接语法中没有的符号来创建新的操作符,比如:operator@。

“ .* ”、“ :: ”、“ sizeof ”、“ ?: ”、“ . ”,这五个运算符不能进行重载

重载运算符至少有一个类类型参数,不能通过运算符重载改变内置类型对象的含义,如:

int operator+(int x,int y)

重载++运算符时,有前置++与后置++,运算符重载函数名都是operator++,无法区分,而C++规定,后置++重载时,增加一个int形参,跟前置++构成函数重载,方便区分。

重载<<和>>时,需要重载为全局函数。若重载为成员函数,this指针默认为第一个形参位置,第一个形参位置是左侧运算对象,调用时就变为:对象<<cout,不符合使用习惯和可读性。重载为全局函数,把ostream/istream放到第一个形参位置,第二个形参位置为类类型对象引用

若运算符重载函数在全局,如何访问对象的私有成员变量?

方法1. 成员放公有

方法2. 对象所在的类提供getxxx函数

方法3. 把运算符重载函数声明为该对象所在类的友元函数

方法4. 把运算符重载函数放在该对象所在类的域里,即使其成为成员函数

运算符重载使用示例:

#include <iostream>
using namespace std;
int arr[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
class Date 
{
public:Date(int year=1,int month=1,int day=1) //默认构造函数{_year = year;_month = month;_day = day;}int Getmday(int Y,int m) {if (m == 2) {if ((Y % 4 == 0 && Y % 100 != 0) || (Y % 400 == 0))return arr[m - 1] + 1;}return arr[m - 1];		}//+的重载Date operator+(int x) //(Date* const this,int x){Date a(*this);//拷贝构造,因为加法不影响两个加数if (x >= 0) {a._day += x;while (a._day > Getmday(a._year,a._month)) {if (a._month == 12) {a._day -= Getmday(a._year, a._month);++a._year;a._month = 1;}else {a._day -= Getmday(a._year, a._month);++a._month;}				}return a;}//x小于0暂不讨论}void Print() {cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};int main() 
{	Date a(2024, 2, 9);Date b(a + 100);a.Print();b.Print();return 0;
}

运行结果:

 

2.6 赋值运算符重载 

赋值运算符重载用于两个已经存在的对象的直接拷贝赋值,注意跟拷贝构造区分开,拷贝构造用于一个要被创建的对象对一个已存在对象进行拷贝以完成自己的初始化。

赋值运算符重载的特点:

1. 必须为成员函数。其参数建议为const修饰的该类类型的引用,如果参数为类类型,那么函数接收实参时还会调用拷贝构造,繁琐且无用。

2. 有返回值,建议返回值类型为该类类型的引用,引用返回可以提高效率,有返回值的目的是为了支持连续赋值场景。

3. 无显式实现时,编译器会自动生成一个默认赋值运算符重载,其会对内置类型成员进行浅拷贝,对自定义类型成员调用它所在的类的赋值重载函数。

4. 如果一个类显式实现了析构函数并释放了资源,那么该类同样需要显式写赋值运算符重载,否则就不需要。

演示示例:

#include <iostream>
using namespace std;
class Date 
{
public:Date(int year = 0, int month = 0, int day = 0) {_year = year;_month = month;_day = day;}Date(const Date& d) //拷贝构造{_year = d._year;_month = d._month;_day = d._day;}Date& operator=(const Date& d)//赋值运算符重载{if (this != &d) //检查是否自己给自己赋值的情况{_year = d._year;_month = d._month;_day = d._day;}return *this;}void Print() {cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};
int main() 
{	Date a(2024, 9, 17);Date b(1,1,1);Date c(2,2,2);c = b = a;a.Print();b.Print();c.Print();return 0;
}

代码运行结果 :

2.7 const成员函数

将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后面。

实际上,const修饰的是该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。

例如:

class Date
{
public:Date(int year=1,int month=1,int day=1){_year = year;_month = month;_day = day;}void Print()const{cout<<_year<<"/"<<_month<<"/"<<_day<<endl;}
private:int _year;int _month;int _day;
};

该代码中Date的成员函数Print是被const修饰的,它隐含的this指针由Date* const this变为const Date* const this 

本文完!

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

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

相关文章

在petalinux工程里添加iperf

在petalinux工程里添加iperf 1,首先确定iperf包在哪里 xxx/components/yocto/layer/ meta-openembedded/meta-oe/recipes-benchmark/iperf3/ 2&#xff0c;然后就是往menuconfig中加&#xff1a; xxx/project-spec/meta-user/conf/user-rootfsconfig文件中 添加&#xff1a; …

maxcompute使用篇

文章目录 maxcompute使用篇1.mongoDB与maxcompute 进行数据同步1.1 基本类型的数据1.2部分复杂类型的数据 2.maxcompute中复杂数据类型解析2.1 get_json_object2.2 json_tuple2.3 处理json几种失效的情况:2.4 STR_TO_MAP、MAP_KEYS2.5 regexp_replace2.6 FROM_JSON2.7 nvl2.8 t…

高级I/O知识分享【epoll || Reactor ET,LT模式】

博客主页&#xff1a;花果山~程序猿-CSDN博客 文章分栏&#xff1a;Linux_花果山~程序猿的博客-CSDN博客 关注我一起学习&#xff0c;一起进步&#xff0c;一起探索编程的无限可能吧&#xff01;让我们一起努力&#xff0c;一起成长&#xff01; 目录 一&#xff0c;接口 epo…

ElasticSearch-2-核心语法集群高可用实战-Week2

ES批量操作 1.批量获取文档数据 这里多个文档是指&#xff0c;批量操作多个文档&#xff0c;搜索查询文档将在之后的章节讲解 批量获取文档数据是通过_mget的API来实现的 (1)在URL中不指定index和type 请求方式&#xff1a;GET 请求地址&#xff1a;_mget 功能说明 &#…

12 Java文件处理之写入、读取:IO流(中):高级流(缓冲流、转换流、序列化流和反序列化流、打印流)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、缓冲流1 字节缓冲流(1)BufferedInputStream:字节缓冲输入流构造方法---- BufferedInputStream(InputStream in):创建一个使用默认缓冲区大小的缓冲输入流。---- BufferedInputStream(In…

【浅水模型MATLAB】尝试复刻SCI论文中的溃坝流算例

【浅水模型MATLAB】尝试复刻SCI论文中的溃坝流算例 前言问题描述控制方程及数值方法浅水方程及其数值计算方法边界条件的实现 代码框架与关键代码模拟结果 更新于2024年9月17日 前言 这篇博客算是学习浅水方程&#xff0c;并利用MATLAB复刻Liang (2004)1中溃坝流算例的一个记录…

特殊文本文件日志技术重点笔记。

特殊文本文件&#xff0c;日志技术(黑马 一套入门 3h) 特殊文件 日志技术 把程序运行的信息&#xff0c;记录到文件中&#xff0c;方便程序员定位bug&#xff0c;并了解程序的执行情况等。 1.为什么要用这些特殊文件 1.1存储单个用户的: 用户名,密码 1.2存储多个用户的&…

数据清洗-缺失值填充-XGboost算法填充

目录 一、安装所需的python包二、采用XGboost算法进行缺失值填充2.1可直接运行代码2.2以某个缺失值数据进行实战2.2.1 代码运行过程截屏&#xff1a;2.2.2 填充后的数据截屏&#xff1a; 三、XGBoost算法原理介绍3.1 XGBoost 的定义3.2 XGBoost 的核心思想3.3 XGBoost 的特点3.…

2024 批量下载知乎回答/文章/想法/专栏/视频/收藏夹,导出 excel 和 pdf

之前分享过文章 2024批量下载知乎回答文章想法专栏收藏夹&#xff0c;公众号文章内容图片封面视频音频&#xff0c;微博内容图片视频评论转发数据&#xff0c;导出excel和pdf &#xff0c;今天再整理分享下知乎知乎回答/文章/想法/专栏/视频/收藏夹下载。 苏生不惑 这个账号已…

Jenkins基于tag的构建

文章目录 Jenkins参数化构建设置设置gitlab tag在工程中维护构建的版本按指定tag的版本启动服务 Jenkins参数化构建设置 选择参数化构建&#xff1a; 在gradle构建之前&#xff0c;增加执行shell的步骤&#xff1a; 把新增的shell框挪到gradle构建之前&#xff0c; 最后保存 …

驱动器磁盘未格式化难题:深度剖析与恢复实践

驱动器磁盘未格式化的深层探索 在数据存储与管理的日常中&#xff0c;驱动器作为我们数字生活的基石&#xff0c;其稳定性直接关系到数据的安全与可用性。然而&#xff0c;当屏幕上赫然出现“驱动器中的磁盘未被格式化”的提示时&#xff0c;许多用户往往感到手足无措&#xf…

Linux 文件与目录操作命令详解

文章目录 前言创建文件1. touch2. vim 文件内容显示3. cat4. more5. less6. head7. tail 文件&#xff08;目录&#xff09;复制、删除和移动8. cp9. rm10. mv 压缩文件与解压缩11. gzip12. zip 和 unzip 创建目录13. mkdir 删除目录14. rmdir 改变工作目录15. cd16. pwd 显示目…

【C语言】联合体枚举的讲解

目录 ✨声明&#xff01;&#xff01;&#xff01;&#xff1a; 联合体与结构体只有一个区别&#xff0c;那就是内存存储方式不同 &#x1f495;1.联合体的声明 &#x1f495;2.联合体内存的存储 &#x1f495;3.联合体字节大小的计算 例题2&#xff1a; ✨4.枚举的声明…

全面掌握 Jest:从零开始的测试指南(下篇)

在上一篇测试指南中&#xff0c;我们介绍了Jest 的背景、如何初始化项目、常用的匹配器语法以及钩子函数的使用。这一篇篇将继续深入探讨 Jest 的高级特性&#xff0c;包括 Mock 函数、异步请求的处理、Mock 请求的模拟、类的模拟以及定时器的模拟、snapshot 的使用。通过这些技…

list从0到1的突破

目录 前言 1.list的介绍 2.list的常见接口 2.1 构造函数&#xff08; (constructor)&#xff09; 接口说明 2.2 list iterator 的使用 2.3 list capacity 2.4 list element access 2.5 list modifiers 3.list的迭代器失效 附整套练习源码 结束语 前言 前面我们学习…

一款源码阅读的插件

文章目录 进度汇报功能预览添加高亮标记高亮风格设置笔记颜色设置数据概览高亮数据详情 结尾 进度汇报 之前提到最近有在开发一个源码阅读的IDEA插件&#xff0c;第一版已经开发完上传插件市场了&#xff0c;等官方审批通过就可以尝鲜了。插件名称&#xff1a;Mark source cod…

防火墙——NAT

目录 NAT NAT分类 旧分类 新分类 NAT配置 源NAT​编辑 配置源NAT地址池​编辑 关于源NAT环路问题 环境如下​编辑 防火墙nat​编辑​编辑 路由器要配置指向11.0.0.0 网段的静态路由​编辑 测试​编辑 如果此时有外网用户直接pingNAT地址&#xff0c;则环路出现。​…

PAT甲级-1016 Phone Bills

题目 题目大意 顾客打长途电话计费&#xff0c;输出每月的账单。输入一行给出一天24小时的计费钱数&#xff0c;注意单位是美分&#xff0c;还要乘以0.01。接下来给出n条记录&#xff0c;每条记录都包括客户名&#xff0c;时间&#xff0c;状态。“on-line”是开始打电话的时间…

专题四_位运算( >> , << , , | , ^ )_算法详细总结

目录 位运算 常见位运算总结 1.基础位运算 2.给一个数 n ,确定它的二进制表示中的第 x 位是 0 还是 1 3.运算符的优先级 4.将一个数 n 的二进制表示的第 x 位修改成 1 5.将一个数n的二进制表示的第x位修改成0 6.位图的思想 7.提取一个数&#xff08;n&#xff09;二进…

如何优雅地处理返回值

我们已经知道了如何优雅的校验传入的参数了&#xff0c;那么后端服务器如何实现把数据返回给前端呢&#xff1f; 返回格式 后端返回给前端我们一般用 JSON 体方式&#xff0c;定义如下&#xff1a; {#返回状态码code:string, #返回信息描述message:string,#返回值data…