C++类和对象(基础篇)

前言:

        其实任何东西,只要你想学,没人能挡得住你,而且其实学的也很快。那么本篇开始学习类和对象(C++的,由于作者有Java基础,可能有些东西过得很快)。

struct在C++中的含义:

        C++兼容C中的struct的用法,并将其升级,可以在里面写函数。

// C++兼容C中的struct的用法
// C++升级struct升级成了类
// 类和对象
// 1个类 实例化 N个对象// 1.类里面可以定义函数
// 2.struct名称可以代表类型
struct Stack
{//成员函数void Init(int n = 4){_arry = (int*)malloc(sizeof(int) * n);if (nullptr == _arry){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}//成员变量int* _arry;size_t _capacity;size_t _top;
};int main()
{struct Stack s1;Stack s;s.Init();return 0;
}

        我们可以不用再写 struct + 结构体名称 去创建对象,相当于已经typedef了,并且可以直接在通过对象调用函数。

        这也体现了C++兼容C的特性。但是C++还是一般并不是用这种用法,一般是使用class来声明一个类。

class Stack
{void Init(int n = 4){_arry = (int*)malloc(sizeof(int) * n);if (nullptr == _arry){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}//成员变量int* _arry;size_t _capacity;size_t _top;
};int main()
{Stack s;//此时我们直接去使用里面的Init方法,发现报错s.Init();return 0;
}

访问权限: 

        上面我们看到报错,这是为啥?这是因为C++中有访问限定符。

1.public修饰的成员在类外可以直接访问

2.protected和private修饰的成员在类外不能直接被访问(此处protected 和 private 是类似的)

3.访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现为止

4.如果后面没有访问限定符,作用域就到 } 即类结束

5.class的默认访问权限为 private ,struct 为 public (因为 struct 要兼容C)

                所以报错的原因是因为前面默认被 private 修饰了。 

class Stack
{
public:void Init(int n = 4){_arry = (int*)malloc(sizeof(int) * n);if (nullptr == _arry){perror("malloc申请空间失败");return;}_capacity = n;_top = 0;}private://成员变量int* _arry;size_t _capacity;size_t _top;
};

        所以一般是成员变量私有,成员方法公有。

        C++建议成员变量前面加_(这是软性建议)。

        我们先创建一个Stack.h头文件,并在里面写入:

Stack.h头文件(声明函数):

#include<iostream>class Stack
{
public:void Init();
private:int* _a;int* _top;int* _capacity;
};

        此时我们在Stack.h头文件中定义一个类并声明其中的一个函数(没有定义),之后在Stack.cpp源文件中定义该函数,此时我们就需要指定类域去定义该函数。因为该函数并不是全局变量,必须指定类域。

Stack.cpp源文件中(定义函数):

void Stack::Init()
{_a = nullptr;_top = 0;_capacity = 0;
}

test.c源文件中(调用函数): 

int main()
{Stack st1;cout << sizeof(st1) << endl;cout << sizeof(Stack) << endl;return 0;
}

        可以发现没有计算函数的大小,因为实例化的对象调用的函数地址都是一样的,每个空间放一份,会造成空间的浪费。 

        所以对象占用的大小,只考虑成员变量,其大小规则和struct类似。

        对于一个空类(就是里面没有任何成员变量),空类的大小为1字节,以确保每个实例都有独一无二的地址,不储存有效数据,标识对象被定义出来了。

this指针:

class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1, d2;d1.Init(1990, 12, 1);d2.Init(1991, 12, 1);d1.Print(), d2.Print();return 0;
}

        这里有一个奇怪的现象,为什么打印的不同,它怎么会知道谁传给了我?其实这里的Print方法中有一个隐含的参数-this,这个this是一个指针。

void Print(Date* this)

        之后只要是成员变联名,它自动识别到了,都相当于前面加上了this指针。

void Print()
{cout << this->_year << "-" << this->_month << "-" << this->_day << endl;
}

        所以其实函数相当于是这样使用的,但是默认不加。所以我们还可以这样调用: 

d1.Print(&d1);

        严格来说是这样写的:

void Print(Date* const this)

注意事项一:

        我们先来观察以下代码:

class A
{
public:void Print(){cout << "Print()" << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}

        这里是其实没有对nullptr去进行解引用,因为默认传入this指针,并不影响对Print函数的使用。 

注意事项二:

        再来观察一下代码:

class A
{
public:void Print(){cout << _a << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();return 0;
}

        但这个结果是运行崩溃。我们来观察他们的区别: 

        this指针存在栈中,因为它是形参,也有可能是寄存器。

类的默认成员函数:

        类有6个默认成员函数,编译器会自动生成6个默认成员函数(很神奇,竟然有6个)。

        默认成员函数:用户没有显示实现,编译器会生成的成员函数成为默认成员函数。

构造函数:

        函数名与类名相同,无返回值,对象实例化编译器自动调用对应的构造函数,构造函数可以重载。分为无参构造和有参构造,类似于初始化函数。和Java使用方式是一样的,不赘述。

        当我们实例化一个对象后,会自动调用构造函数。

class Date
{
public:Date(){_year = 1;_month = 1;_day = 1;}void Init(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << this->_year << "-" << this->_month << "-" << this->_day << endl;this->Fanacy();}void Fanacy(){cout << "hehe" << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;d1.Print();return 0;
}

        观察以下代码:

Date()
{_year = 1;_month = 1;_day = 1;
}Date(int year, int month, int day)
{this->_year = year;this->_month = month;this->_day = day;
}

        此时我们有两个构造函数,一个有参一个无参,并通过主函数这样调用:

int main()
{Date d1;Date d2(2, 3, 4);d1.Print();d2.Print();return 0;
}

        如果是无参的不要带括号,只是为了和函数声明区分开。 

Date d1;
Date d2(2, 3, 4);Date d1();//函数声明

        构造函数一般喜欢写成全缺省函数。

Date(int year = 1, int month = 1, int day = 1)
{this->_year = year;this->_month = month;this->_day = day;
}

        这样就可以把无参构造省略了,非常方便。 

        记住缺省函数定义和声明不能同时给,规定只能在声明的时候给,定义的时候不给。

        如果我们写了显示的默认成员函数,那么编译器则不会在生成默认成员函数,也是和Java一样,救急不救穷。

        编译器自动生成的构造函数,对于内置类型成员变量不做处理(也就是int了,double了等等基础类型),当然有些编译器会处理。

        不传参数就可以调用的函数就是默认构造。

        C++11为了解决初始化问题,我们可以在定义成员变量时给定缺省值。

class Date
{
public:void Print(){cout << this->_year << "-" << this->_month << "-" << this->_day << endl;}private://给缺省值int _year = 1;int _month = 1;int _day = 1;
};int main()
{Date d1;d1.Print();return 0;
}

        默认构造函数只能有一个。注意:无参构造函数、全缺省函数、编译器默认生成构造函数,都可以认为是默认构造函数。

        3个只能存在一个。

析构函数:

        析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作使用编译器完成的。而对象在销毁是会自动调用析构函数,完成对象中资源的清理工作。

        其也是一个特殊的成员函数,特征如下:

        析构函数名是在类前加上字符~;无参数无返回类型;一个类只能有一个析构函数。若未显示定义,系统会自动生成默认的析构函数。注意:析构函数不能重载;对象生命周期结束时,C++编译系统自动调用析构函数。

~Date()
{cout << "这是显示调用的析构函数!" << endl;
}

        析构函数我们也可以显示调用。 

d1.~Date();

        不是所有类都需要写析构函数,因为不需要释放空间。

        编译器默认的析构函数对内置类型不做处理,对自定义类型去调用它的析构函数。

拷贝构造:

        拷贝构造也是特殊的成员函数,特征如下:

        拷贝构造函数是构造函数的一个重载形式;拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

        若未显示定义,编译器会生成默认的拷贝构造函数。默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝或者值拷贝。

class A
{
public:A(int a = 100){_a = a;}A(A& a){_a = a._a;cout << "这里调用了拷贝构造!" << endl;}void Print(){cout << _a << endl;}
private:int _a;
};void func(A a)
{a.Print();
}int main()
{A a1(5);func(a1);return 0;
}

        可以看到,我们并没有去调用任何的拷贝构造参数,但是调用了func函数之后却调用了。

        这是因为这是传值传参,自定义类型对象传值传参要调用拷贝构造。 除非传入指针或者使用引用才不会调用拷贝构造。

        这样就会引起死递归。所以要修改为引用: 

A(const A& a)
{_a = a._a;cout << "这里调用了拷贝构造!" << endl;
}

        我们一般习惯往里面写入const,是为了防止修改被拷贝的内容。

        这里相当于权限的缩小。

// 下面的两种写法是等价的
A a2(a1);
A a3 = a2; //这也是拷贝构造

        默认构造会实现浅拷贝,也就是不会拷贝引用类型。 默认构造会实现浅拷贝,也就是内置类型的拷贝。

总结:

        如果没有管理资源,一般不要写拷贝构造,默认生成的即可使用;如果都是自定义类型成员,内置类型成员没有指向资源,也类似默认生成的拷贝构造就可以(比如用栈实现队列);一般情况下,不需要显示写析构函数,就不需要写拷贝构造;如果内部有指针或者一些值指向资源,需要显示写析构,通常就需要显示写拷贝构造完成深拷贝。

赋值运算符重载函数: 

        赋值运算符重载是默认成员函数,不写编译器默认生成。用户没有显示实现时,会以值的方式逐字节拷贝。和拷贝构造函数类似。

        复制运算符重载不能写成全局函数,这是规定!

运算符重载:

        运算符重载:是具有特殊函数名的函数,也具有其返回值类型,函数名及参数和返回值与普通函数类似。

        函数名字为:关键字operator后面需要重载运算符符号。

class Date 
{
public:Date(int year = 1, int month = 1, int day = 1){this->_year = year;this->_month = month;this->_day = day;}Date(Date& d){_year = d._year;_month = d._month;_day = d._day;}void Print(){cout << this->_year << "-" << this->_month << "-" << this->_day << endl;}//private://给缺省值int _year = 1;int _month = 1;int _day = 1;
};//大于
bool Compare1(const Date& d1, const Date& d2)
{if (d1._year > d2._year){//年大就大return true;} else if (d1._year == d2._year){if (d1._month > d1._month){//月大就大return true;}else if (d1._month == d2._month){//天大就大return d1._day > d2._day;}}
}//小于
bool Compare2(const Date& d1, const Date& d2)
{if (d1._year < d2._year){//年小就小return true;}else if (d1._year == d2._year){if (d1._month < d1._month){//月小就小return true;}else if (d1._month == d2._month){//天小就小return d1._day < d2._day;}}
}//等于
bool Compare1(const Date& d1, const Date& d2)
{if (d1._day == d2._day && d1._year == d2._year && d1._month == d1._month){return true;}return false;
}int main()
{Date d1(2024, 4, 10);Date d2(2024, 4, 9);cout << Compare1(d1, d2) << endl;//cout << (d1 > d2) << endl;return 0;
}

        比如此时我对日期类进行比较,写了3个函数来实现,这样很麻烦,但是有操作符重载就会很方便。

cout << (d1 > d2) << endl;

        比如此时我们就像通过这样来完成这个比较方法。 

        重载操作符必须有一个类类型参数,也就是说不能这样写:

//运算符重载是函数,以下形式非法!
int operator-(int i, int j)

        .* :: sizefof  ? :  . 这5个运算符不能重载。 

//大于
bool operator>(const Date& d1, const Date& d2)
{if (d1._year > d2._year){//年大就大return true;}else if (d1._year == d2._year){if (d1._month > d1._month){//月大就大return true;}else if (d1._month == d2._month){//天大就大return d1._day > d2._day;}}
}

        之后可以直接这样使用:

cout << (d1 > d2) << endl;

        插一嘴,其中.*是一个运算符(蒙了吧,我也蒙了,解释一下)。

class OB
{
public:void func(){cout << "func:" << endl;}
};//重命名函数指针
typedef void(OB::* Ptr)();//重命名int main()
{//这里必须使用&Ptr fp = &OB::func;OB tmp;//此时也就用到了.*这个操作符(tmp.*fp)();//通过函数指针调用函数return 0;
}

        这里我们使用到了.*。

        一个类要重载哪些元素符是看需求。

class Date 
{
public:Date(int year = 1, int month = 1, int day = 1){this->_year = year;this->_month = month;this->_day = day;}bool operator==(const Date& d){return _day == d._day&& _year == d._year&& _month == d._month;}private://给缺省值int _year = 1;int _month = 1;int _day = 1;
};int main()
{Date d1(20, 1, 3);Date d2(20, 1, 4);//显示调用d1.operator==(d2);//这样就没有优势了//直接写,转换调用,编译器会转换为 operator==(d1, d2)d1 == d2;return 0;
}

        此时我们发现,我都是在类外定义的函数,也就意味着要把类中的成员变量都变为公有的才能这样写。 

        有3种解决方法:提供这些成员get和set方法;友元(后期讲);重载为成员函数。

        相信各位对get和set方法都了解,我们不再赘述。

class A
{
public:A(int a = 100){_a = a;}A(const A& a){_a = a._a;cout << "这里调用了拷贝构造!" << endl;}A operator=(const A& a){//这里面最好加上返回值,这样就可以连续赋值并且不会出错_a = a._a;return *this;}void Print(){cout << _a << endl;}
private:int _a;
};int main()
{A a1(100);A a2;//拷贝一个A a3;a3 = a2 = a1;a3.Print();return 0;
}

        我们在使用操作符重载的时候,最好加上返回值,这样可以连续赋值不会出错。

注意事项:        

class Date 
{
public:Date(int year = 1, int month = 1, int day = 1){this->_year = year;this->_month = month;this->_day = day;}Date(const Date& d){cout << "这里调用了拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}bool operator==(const Date& d){return _day == d._day&& _year == d._year&& _month == d._month;}//private://给缺省值int _year = 1;int _month = 1;int _day = 1;
};bool operator==(const Date& d1, const Date& d2)
{return d1._day == d2._day&& d1._year == d2._year&& d1._month == d2._month;
}Date func()
{Date d;return d;
}int main()
{Date d1(20, 1, 3);Date d2(20, 1, 4);func();return 0;
}

        这里注意我们调用了func函数,返回的是Date类,会去调用类中的拷贝构造!但是可以发现,执行结果并没有执行拷贝构造中的语句,这是为啥?

        但是确实会调用拷贝构造,是因为优化没有调用。

        编译器在某些情况下会对代码进行优化,以提高执行效率。其中之一就是返回值优化(Return Value Optimization,RVO)。RVO 是一种优化技术,它可以避免不必要的拷贝构造函数调用。
        在 func() 函数中,返回了一个局部对象 d。如果编译器启用了 RVO,它会直接将 d 放在函数调用者的位置,而不是创建临时副本。这样,拷贝构造函数就不会被调用。

        但是我们严谨一点,这只是编译器帮助了我们优化,此时我们如何才能让其不拷贝?就是返回引用。

Date& func()
{Date d;return d;
}

        传值返回是返回d的拷贝,引用返回是d的别名。

class Date 
{
public:Date(int year = 1, int month = 1, int day = 1){this->_year = year;this->_month = month;this->_day = day;}Date(const Date& d){cout << "这里调用了拷贝构造" << endl;_year = d._year;_month = d._month;_day = d._day;}bool operator==(const Date& d){return _day == d._day&& _year == d._year&& _month == d._month;}void Print(){cout << _year << " " << _month << " " << _day << endl;}~Date(){cout << "调用了析构" << endl;_year = -1;}
//private://给缺省值int _year = 1;int _month = 1;int _day = 1;
};bool operator==(const Date& d1, const Date& d2)
{return d1._day == d2._day&& d1._year == d2._year&& d1._month == d2._month;
}Date& func()
{Date d;return d;
}int main()
{Date& d3 = func();d3.Print();return 0;
}

        如果不用引用返回,返回的是d的拷贝,这里d有是临时拷贝,临时对象具有常性。 当然,d3接收以后就可以修改它的属性。

Date& func()
{Date d(1022, 1, 3);return d;
}int main()
{Date& d3 = func();d3.Print();return 0;
}

        再来观察以下代码:

Date& func()
{Date d(1022, 1, 3);return d;
}int funcs()
{int a = 1;int b = 2;int c = 3;return a + b + c;
}int main()
{Date& d3 = func();d3.Print();funcs();return 0;
}

        此时我们在调用一个函数,发现d3里面的值也已经改变,这是因为:

小结: 

        返回对象生命周期到了,会析构,传值返回。

        返回对象生命周期没到,不会析构,传引用返回。

        出了作用域,返回对象还没有析构,就可以用引用返回,减少拷贝。

         为了优化程序,我们一般对于类的返回使用的是引用返回。

        所以最好一般最好返回值,不要返回引用。

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

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

相关文章

开机弹窗找不到OpenCL.dll是怎么回事,哪种修复方法更推荐

当用户在操作电脑过程中遇到系统提示“OpenCL.dll丢失”时&#xff0c;这究竟是怎么一回事呢&#xff1f;OpenCL.dll&#xff0c;作为Open Computing Language&#xff08;开放计算语言&#xff09;的重要动态链接库文件&#xff0c;它在图形处理器&#xff08;GPU&#xff09;…

爬虫:爬取豆瓣电影

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 上篇我们将到如何利用xpath的规则&#xff0c;那么这一次&#xff0c;我们将通过案例来告诉读者如何使用Xpath来定位到我们需要的数据&#xff0c;就算你不懂H5代码是怎么个嵌套或者十分复…

my-room-in-3d中的电脑,电视,桌面光带发光原理

1. my-room-in-3d中的电脑&#xff0c;电视&#xff0c;桌面光带发光原理 最近在github中&#xff0c;看到了这样的一个项目&#xff1b; 项目地址 我看到的时候&#xff0c;蛮好奇他这个光带时怎么做的。 最后发现&#xff0c;他是通过&#xff0c;加载一个 lightMap.jpg这个…

C++语法|如何写出高效的C++代码(一)|对象使用过程中背后调用了哪些方法(构造和析构过程)?

文章目录 再探拷贝构造函数和重载复制运算符实例化新对象和赋值操作强转为类类型指针和引用时临时对象的构造和析构过程 考考你问题答案 再探拷贝构造函数和重载复制运算符 实例化新对象和赋值操作 首先我们写一个类&#xff0c;实现它的拷贝构造并重载赋值运算符。 class T…

数值计算方法——大题题型总结

目录 一、绝对误差限、相对误差限 1.1 例题 1.2 解题套路 1.3 题解 二、敛散性、收敛速度 2.1 例题 2.2 解题套路 2.3 题解 三、牛顿迭代法 3.1 例题 3.2 解题套路 3.3 题解 四、割线法 4.1 例题 4.2 解题套路 ​4.3 题解 五、列主元素消去法 5.1 例题 5.…

python爬虫实战

import requests import json yesinput(输入页数&#xff1a;) yesint(yes)headers {"accept": "application/json, text/plain, */*","accept-language": "zh-CN,zh;q0.9","content-type": "application/json",…

JAVA基础之jsp标准标签

jsp动作标签实现实例化一个实体类 <jsp:useBean id"标识符" class"java类名" scope"作用范围"> 传统的java方式实例化一个实体类 Users user new Users(); <%%> id: 对象名 * class:类 创建对象时,完全限定名(包名…

Linux基础之yum和vim

目录 一、软件包管理器yum 1.1 软件包的概念 1.2 软件包的查看 1.3 软件包的安装和删除 二、Linux编辑器之vim 2.1 vim的基本概念 2.2 正常模式&#xff08;命令模式&#xff09; 2.3 底行模式 2.4 输入模式 2.5 替换模式 2.6 视图模式 2.7 总结 一、软件包管理器yu…

嵌入式Linux学习第四天启动方式学习

嵌入式Linux学习第四天 今天学习I.MX6U 启动方式详解。I.MX6U有多种启动方式&#xff0c;可以从 SD/EMMC、NAND Flash、QSPI Flash等启动。 启动方式选择 BOOT 的处理过程是发生在 I.MX6U 芯片上电以后&#xff0c;芯片会根据 BOOT_MODE[1:0]的设置来选择 BOOT 方式。BOOT_M…

Spring - 9 ( 10000 字 Spring 入门级教程 )

一&#xff1a; MyBatis XML 配置文件 Mybatis 的开发有两种方式&#xff1a; 注解XML 我们已经学习了注解的方式, 接下来我们学习 XML 的方式 MyBatis XML 的方式需要以下两步: 配置数据库连接字符串和 MyBatis写持久层代码 1.1 配置连接字符串和 MyBatis 此步骤需要进…

STC8增强型单片机开发 【第一个程序 - 点亮第一盏灯】

目录 一、创建项目 1. 创建一个新的项目 ​编辑 2. 配置开发板信息 ​编辑 3. 取消汇编配置 4. 项目结构 二、编码实现 1. 项目准备 2. 代码实现 点灯&#xff1a; 熄灯&#xff1a; 3. 编译烧录运行 配置编译输出 保存和编译代码 ​编辑 烧录 一、创建项目 1. …

OceanBase 如何实现多层面的资源隔离

OceanBase的资源隔离涵盖了多个方面&#xff0c;如物理机器间的隔离、不同租户之间的隔离、同一租户内的隔离&#xff0c;以及针对大型查询请求的隔离等。在实际应用OceanBase的过程中&#xff0c;我们经常会遇到这些操作场景或产生相关需求。这篇文章针对这些内容进行了简要的…

阿里云SLB监听虚拟服务器组时,既有部署在k8s容器里的应用,又有部署在ecs机器上的应用,k8s应用无法连接部署在ecs机器上的应用

一、背景 阿里云SLB可以添加多个监听端口&#xff0c;包括http和tcp&#xff0c;但是当被添加的后端应用&#xff0c;既有部署在k8s里&#xff0c;也有部署在ecs机器里。同一个slb下&#xff0c;这种混合方式的监听&#xff0c;会导致部署在k8s应用中的应用无法连接后者&#…

Spring扩展点(一)Bean生命周期扩展点

Bean生命周期扩展点 影响多个Bean的实例化InstantiationAwareBeanPostProcessorBeanPostProcessor 影响单个Bean的实例化纯粹的生命周期回调函数InitializingBean&#xff08;BeanPostProcessor 的before和after之间调用&#xff09;DisposableBean Aware接口在生命周期实例化过…

内存卡突然罢工?数据恢复有高招!

内存卡作为我们日常生活中常见的存储设备&#xff0c;广泛应用于手机、相机等设备中。然而&#xff0c;有时我们会遇到内存卡损坏打不开的情况&#xff0c;这时该如何应对呢&#xff1f;本文将为您详细解析内存卡损坏的原因&#xff0c;并提供有效的数据恢复方案&#xff0c;帮…

FPGA第二篇,FPGA与CPU GPU APU DSP NPU TPU 之间的关系与区别

简介&#xff1a;首先&#xff0c;FPGA与CPU GPU APU NPU TPU DSP这些不同类型的处理器&#xff0c;可以被统称为"处理器"或者"加速器"。它们在计算机硬件系统中承担着核心的计算和处理任务&#xff0c;可以说是系统的"大脑"和"加速引擎&qu…

如何进行Go语言的性能测试和调优?

文章目录 开篇一、性能测试1. 使用标准库中的testing包2. 使用第三方工具 二、性能调优1. 优化算法和数据结构2. 减少不必要的内存分配和垃圾回收3. 并发和并行 结尾 开篇 Go语言以其出色的性能和简洁的语法受到了广大开发者的喜爱。然而&#xff0c;在实际开发中&#xff0c;…

Linux进程——Linux进程间切换与命令行参数

前言&#xff1a;在上一篇了解完进程状态后&#xff0c;我们简单了解了进程优先级&#xff0c;然后遗留了一点内容&#xff0c;本篇我们就来研究进程间的切换&#xff0c;来理解上篇提到的并发。如果对进程优先级还有没理解的地方可以先阅读&#xff1a; Linux进程优先级 本篇…

Python程序设计 函数(三)

练习十一 函数 第1关&#xff1a; 一元二次方程的根 定义一个函数qg&#xff0c;输入一元二次方程的系数a,b,c 当判别式大于0&#xff0c;返回1和两个根 当判别式等于0&#xff0c;返回0和两个根 当判别式小于0&#xff0c;访问-1和两个根 在主程序中&#xff0c;根据函数返回…

Vue3:menu导航栏出现多个同一跳转路径的菜单处理

文章目录 需求整理实现思路实现过程 需求整理&#xff0c;实现思路 最近公司想将之前老的项目整理出来&#xff0c;因为这个老项目内容太杂什么页面都往里面塞&#xff0c;导致菜单特别多&#xff0c;公司就像将这个老的项目迁出来&#xff0c;这个旧的项目本来是后端PHP写的。…