<C++>类和对象-下

news2025/1/12 10:54:04

 


目录

一、构造函数的初始化

1. 构造函数体赋值

2. 初始化列表 

2.1 概念

2.2 隐式类型转换式构造

2.3 explicit关键字

二、static静态成员

1. 概念

2. 特性

三、友元

1. 友元函数

2.友元类

四、内部类

1. 概念

五、匿名对象

1. const引用匿名对象

2. 匿名对象的隐式类型转换 

总结


一、构造函数的初始化

1. 构造函数体赋值

在创建对象时,编译器都过调用构造函数,给对象中各个成员变量一个合适的初始值

class Date
{
public:
 Date(int year, int month, int day)
 {
     _year = year;
     _month = month;
     _day = day;
 }
 
private:
     int _year;
     int _month;
     int _day;
};
        虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称作为类对象成员的初始化,构造 函数体中的语句只能将其称作为赋初值 ,而不能称作初始化。因为 初始化只能初始化一次,而构造函数体内 可以多次赋值

        那么真正的初始化在哪里呢?

2. 初始化列表 

初始化列表是构造函数的一部分

2.1 概念
        初始化列表:以一个 冒号开始 ,接着是一个以 逗号分隔的数据成员列表 ,每个 " 成员变量 " 后面跟一个 放在括 号中的初始值或表达式。
class Date
{
public:
     Date(int year, int month, int day)
     : _year(year)
     , _month(month)
     , _day(day)
 {}
 
private:
     int _year;
     int _month;
     int _day;
};
【注意】
1. 每个成员变量在初始化列表中最多只能出现一次(初始化只能初始化一次)
2. 类中包含以下成员,必须放在初始化列表位置进行初始化
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(该类没有默认构造函数)

const 与 &(引用)共同特征就是都必须在定义时初始化。在类内,成员变量只是声明,在对象实例化时,才对对象整体定 义开空间,而对象的成员定义的地方就在构造函数处——初始化列表(构造函数内不是定义,是赋值,真正的定义在初始化列表)

对于自定义类型,如果没有在初始化列表初始化,那么编译器会自动调用其自身的构造函数进行初始化,而对于内置类型,如果没有在初始化列表初始化,那么其值是随机的,编译器对其不做处理,所以C++11新增:对类内成员函数的声明处,允许给缺省值,就是为了初始化时给初始化列表;如果在初始化列表处对内置类型初始化,那么缺省值就不管用了

回顾:

        默认构造函数:编译器自动生成的、自己写的全缺省的、无参数的,共三种

当该类没有默认构造函数,就意味着自己手写的构造函数不是全缺省参数,需要传参,所以如果没有在初始化列表初始化,那么编译器就会不知道如何初始化该类的成员变量,这就是为什么如果该类没有默认构造函数就必须要在初始化列表初始化的原因

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout << "A(int a = 0)" <<endl;
	}
private:
	int _a;
};

class B
{
public:
	// 初始化列表:对象的成员定义的位置
	B(int a, int& ref)
		:_ref(ref)
		,_n(1)
		,_x(2)
        ,_aobj(10)
	{
		//_n = 0;
		//_ref = ref;
	}

private:
	// 声明
	A _aobj;	  // 没有默认构造函数

	// 特征:必须在定义的时候初始化
	int& _ref;	  // 引用
	const int _n; // const

	int _x = 1;  // 这里1是缺省值,缺省值是给初始化列表的
};

int main()
{
	int n = 10;
	// 对象整体定义
	B bb1(10, n); 
	//B bb2(11, 2);

	return 0;
}

那么,我们是否能使用初始化列表完全取代构造函数体内赋值的操作取代了呢?

        答:不能,因为如果我们malloc空间后,返回的是指针,我们是需要进行判空的,该操作在初始化列表中,是很不方便的编写的,此外memset等函数或操作都不能很方便的写在初始化列表中,总有一些操作是初始化列表做不了的

3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。

        所以,我们在初始化时尽量用初始化列表,当遇到额外的不方便的操作,放在构造函数体内即可 

4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关  

class A
{
public:
     A(int a)
     :_a1(a)
     ,_a2(_a1)
 {}
 
 void Print() 
 {
     cout<<_a1<<" "<<_a2<<endl;
 }
private:
     int _a2;
     int _a1;
}

int main() 
{
     A aa(1);
     aa.Print();
}

A. 输出1 1
B.程序崩溃
C.编译不通过
D.输出1 随机值

        答案为D, 初始化列表中的初始化顺序与成员变量在类内的声明顺序相同,此题中先初始化_a2,再初始化_a1,所以_a2为随机值,_a1为1

        在构造函数体内,赋值顺序与语句有关,不受此影响

        如果我们在类中的变量声明处给成员变量一缺省值,那么该成员变量会在构造函数的初始化列表中被初始化为缺省值(缺省值已经给出,在初始化列表处必然会被初始化为缺省值,这是我们不能改变的),但是当我们实例化对象的时候不想用这一缺省值时,我们可以在构造函数内进行赋值修改这一成员变量的值 

2.2 隐式类型转换式构造

我们来看一个隐式类型转换的构造

class A
{
public:
	A(int a)
		:_a(a)
	{} 
private:
	int _a;
};

int main()
{
    A aa1(1);
    A aa2 = 2;

    //int i = 10;
    //double d = i;

    return 0;

}

        ·这里的 A aa2 = 2隐式类型转换,将2整形转换成自定义类型A,类似于int型变量i赋值给double型变量d,这其中会发生隐式类型转换,产生一个临时变量存储double型i,再将double型i赋值给d;同理,A aa2 = 2意思为:2构造一个A的临时变量,临时变量再拷贝构造aa2,但是编译器不能“容忍”效率低下的类型转换(一般对于连续的构造、拷贝构造,编译器都会优化),编译器优化为将 2 作为参数直接构造aa2

        再来看另一种情况:

A& aa3 = 2;

 错误:无法从“int” 转换为A&由于这里不是连续的构造和拷贝构造,它仅仅是构造,因为引用&不是拷贝,所以这里还是需要临时变量,又因为2在构造临时对象时,该临时对象具有常性,直接用引用类型接收,权限放大,出现错误,所以aa3要用const修饰

const A& aa3 = 2;
2.3 explicit关键字

有没有办法能不允许其隐式类型转换呢?这里有关键字explicit

class A
{
public:
	explicit A(int a)
		:_a(a)
	{
		cout << "A(int a)" << endl;
	} 
private:
	int _a;
};

使用explicit关键字加在构造函数前,主函数内的 A aa2 = 2 将不再允许临时类型转换,程序报错 

二、static静态成员

1. 概念

        声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰成员函数,称之为静态成员函数静态的成员变量一定要在类外进行初始化

面试题:实现一个类,计算程序中创建出了多少个类对象

        我们正常想法可能是定义全局变量记录构造函数、拷贝构造函数调用次数,当调用析构函数时,全局变量值减一,最后输出大小

int _scount = 0;

class A
{
public:
	A() { ++_scount; }
	A(const A& t) { ++_scount; }
	~A() { --_scount; }
	/*static int GetACount() { return _scount; }*/
private:
	static int _scount;
};

A aa0;

void Func()
{
	static A aa2;
	cout << __LINE__ << ":" << _scount << endl;

	// 全局变量的劣势:任何地方都可以随意改变
	_scount++;
}

int main()
{
	cout <<__LINE__<<":"<< _scount << endl;  // 1
	A aa1;
	
	Func();  // 3
	Func();  // 3

	return 0;
}

        __LINE__宏定义,输出当前代码执行到的行数 ,我们在22行的Func函数中添加了_scount++,最终的输出变为了4(由于静态变量存储在静态区,aa2第一次定义后变量没有销毁,在第二次调用该行代码时,并没有重复定义,所以正确答案_scount应为3,但是在认为修改了一小步后,结果出错),这就直接体现了全局变量的劣势所在:任何地方都可以随意改变。

        所以我们将_scount封装在类中,使用static修饰,成为静态成员变量,所谓静态成员变量与成员变量的区别在于成员变量属于每一个类对象,储存在对象里面,而静态成员变量属于类,属于类的每个对象共享,存储在静态区,所以不能在初始化列表中对静态成员变量进行初始化,因为它不属于某一对象的成员变量。

        对于静态成员变量,在类外的全局位置进行初始化,虽然它是私有的,但是在全局初始化静态变量时,这一操作是被允许的。

        且静态成员变量不能给缺省值,缺省值是给初始化列表的

int A::_scount = 0;

        但是对于在类外使用 A::_scount 进行访问时就不允许了,会受到private的保护,如果是public那么就可以在类外使用 A::_scount 进行访问。

        那么如何在类外访问private保护的静态成员变量呢?

  • 构造一个成员函数 GetACount( )  ,将静态成员变量作为返回值

        可是如果没有实例化对象,那么就不能使用成员函数进行访问,这时我们可以将该成员函数使用static修饰,使其成为静态成员函数,就可以在没有对象的情况下在类外进行访问静态成员函数,这是因为静态成员函数没有this指针,在类外指定了类域和访问限定符后就可以访问该函数,并且不能在静态成员函数内访问成员变量,因为想要访问成员变量都要用到 this 指针。

        由于静态成员函数没有this指针,所以在其函数内不能调用其余成员函数,因为没有函数调用地址,但是其余的成员函数可以调用静态成员函数,因为有this指针且都在类中,相当于在一个“大家庭”,所以普通成员函数可以访问静态成员函数。

        在类外能访问到静态成员变量是因为它属于类,不属于某一单独的对象。

cout << A::GetACount() << endl;

    

例题:

思路:使用n次构造函数并结合静态成员变量,即可巧妙的解决该问题

class Sum
{
public:
    Sum()
    {
        _ret += _i;
        _i++;
    }

    static int Get_ret()
    {
        return _ret;
    }
private:
    static int _i;
    static int _ret;
};

int Sum::_i = 1;
int Sum::_ret = 0;

class Solution {
public:
    int Sum_Solution(int n) 
    {
        //这里涉及到了变长数组的概念,C++11允许变长数组
        Sum a[n];
        return Sum::Get_ret();
    }
};

例题二:

        设计一个类,使得在类外只能在栈或堆上创建对象

        在类外,我们可以实例化栈、静态区、堆上的对象。但是此时我们加上了限制,如只能在栈上实例化对象,那么为了避免在其他内存空间创建对象,我们直接用private修饰类的构造函数相当于“封死”外部任何形式的实例化,使得只能在类内实例化之后再返回实例化对象但此时又出现一个问题,普通成员函数参数列表内默认有一个类的对象,this指向该对象,可是我们还没有创建对象,我们的目的就是创建对象,这就矛盾了,成为了“先有鸡还是先有蛋”的问题

        此时,静态成员函数就登场了,由于静态成员函数没有this指针,就代表了它不需要参数,这就完美解决了上面的问题

class A
{
public:
	static A GetStackObj()
	{
		A aa;
		return aa;
	}

	static A* GetHeapObj()
	{
		return new A;
	}
private:
	A()
	{}

private:
	int _a1 = 1;
	int _a2 = 2;
};

int main()
{
	//static A aa1;   //  静态区
	//A aa2;          //  栈 
	//A* ptr = new A; //  堆

	A::GetStackObj();
	A::GetHeapObj();

	return 0;
}

2. 特性

1. 静态成员 为所有 类对象所共享,不属于某个具体的实例
2. 静态成员变量 必须在类外定义 定义时不添加 static关键字
3. 类静态成员即可用类名  ::  静态成员或者对象 .静态成员来访问
4. 静态成员函数 没有隐藏的this 指针,不能访问任何非静态成员
5. 静态成员和类的普通成员一样,也有 publicprotectedprivate3种访问级别,也可以具有返回值

三、友元

友元分为:友元函数 友元类
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

1. 友元函数

        友元函数可以 直接访问 类的 私有 成员,它是 定义在类外部 普通函数 ,不属于任何类,但需要在类的内部声明,声明时需要加friend 关键字。
说明 :

  1. 友元函数可访问类的私有和保护成员,但不是类的成员函数
  2. 友元函数不能用const修饰
  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  4. 一个函数可以是多个类的友元函数
  5. 友元函数的调用与普通函数的调用和原理相同

2.友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

  1. 友元关系是单向的,不具有交换性。
  2. 友元关系不能传递
如果 B A 的友元, C B 的友元,则不能说明 C是 A 的友元。

四、内部类

1. 概念

        如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类外部类对内部类没有任何优越的访问权限。
注意:内部类就是外部类的友元类。注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员但是外部类不是内部类的友元 内部类天生是外部类的友元
特性:
1. 内部类定义在外部类的 publicprotectedprivate都是可以的。
2. 注意内部类可以直接访问外部类中的 static、枚举成员,不需要外部类的对象/ 类名
3. sizeof( 外部类)= 外部类,和内部类没有任何关系
class A
{
private:
     static int k;
     int h;
public:
     class B
     {
     public:
         void foo(const A& a)
         {
             cout << k << endl;//OK
             cout << a.h << endl;//OK
         }
     };
};

int A::k = 1;

int main()
{
     A::B b;
     b.foo(A());
 
     return 0;
}

内部类受外部类的访问限定符限制公有内部类、私有内部类

五、匿名对象

有名对象——生命周期在当前函数的局部域

class A
{
public:
    A(int a = 0)
        :_a(a)
    {
        cout << "A(int a)" << endl;
    }

    ~A()
    {
        cout << "~A()" << endl;
    }
private:
    int _a;
};

int main()
{
    //有名对象
    A aa(1);

    //匿名对象
    A(2);

    return 0;
}

匿名对象即用即销毁,生命周期在当前行。

        一般来说,我们要访问类的成员函数,都要先有对象,再利用对象访问成员,(用类型是不能访问成员的!) 当我们没有实例化对象时,我们就可以利用匿名对象来访问,例

class Solution {
public:
    int Sum_Solution(int n) {
        cout << "Sum_Solution" << endl;
        //...
        return n;
    }
};

int main()
{
    Solution s1;
    s1.Sum_Solution(10);

    Solution().Sum_Solution(20);

    return 0;
}

         若构造函数内需要传参,那么在匿名对象()内加上参数即可,匿名对象与有名对象的区别就在于有没有名字

1. const引用匿名对象

        一般情况,匿名对象生命周期在当前行。因为匿名对象具有常性,我们用引用接收是错误的,权限放大,我们需要用const引用接收,这时我们再运行程序,会发现该临时对象生命周期改变,在局部域。这是为了防止野引用

//A& ra = A(1);    //匿名对象具有常性

//const引用延长了匿名对象的生命周期
const A& ra = A(1);

2. 匿名对象的隐式类型转换 

void push_back(const string& s)
{
    cout << "push_back:" << s << endl;
}

int main()
{
    //1
    string str("11111");
    push_back(str);

    //2
    push_back(string("222222"));

    //3
    push_back("222222");
    
    return 0;
}

2是匿名对象,3是临时对象,两者相同都具有常性,所以形参都要有const修饰

void Func1(A aa)
{}

A Func5()
{
    A aa;
    return aa;
}

int main()
{
    A ra1 = Func5(); // 拷贝构造+拷贝构造 ->优化为拷贝构造
    cout << "==============" << endl;
    A ra2;
    ra2 = Func5();
    

    //A aa1;
    //Func1(aa1); // 不会优化

    //Func1(A(1)); // 构造+拷贝构造 ->优化为构造
    //Func1(1);    // 构造+拷贝构造 ->优化为构造

    //A aa2 = 1;  // 构造+拷贝构造 ->优化为构造


    return 0;
}

 

        对于ra1,由两次的连续的拷贝构造(返回临时遍历),编译器自动优化为一次拷贝构造

        对于ra2,由于是两行代码,构造不连续,编译器不会优化,会成为构造、构造、拷贝构造、析构、赋值运算符重载、析构 

        所以,对于能一行写完的对象之间的操作,尽量不写成两行,这样不仅繁琐,还会干扰编译器


总结

        本节补充了类和对象的剩余细节,至此,我们较为完善的学习了C++类和对象。

        类和对象的细节繁多,较为难学,根据文章内容的理解再查阅C++对应书籍,就会更加明了。

最后,如果小帅的本文哪里有错误,还请大家指出,请在评论区留言(ps:抱大佬的腿),新手创作,实属不易,如果满意,还请给个免费的赞,三连也不是不可以(流口水幻想)嘿!那我们下期再见喽,拜拜!

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

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

相关文章

华为云云耀云服务器L实例评测 | 实例场景体验之搭建接口服务:通过华为云云耀云服务器构建 API 服务

华为云云耀云服务器L实例评测 &#xff5c; 实例场景体验之搭建接口服务&#xff1a;通过华为云云耀云服务器构建 API 服务 介绍华为云云耀云服务器 华为云云耀云服务器 &#xff08;目前已经全新升级为 华为云云耀云服务器L实例&#xff09; 华为云云耀云服务器是什么华为云云…

数据结构笔记(王道408)

文章目录 前言绪论数据结构基本概念基本概念数据结构三要素与ADT 算法基本概念算法定义算法五个基本特性好算法的进阶特性 算法复杂度时间复杂度空间复杂度 线性表 前言 数据结构的笔记相比于其他3门&#xff0c;笔记的重要性要低很多&#xff0c;毕竟对于选择408的同学来说&a…

Python学习笔记之运算符的使用

Python学习笔记之运算符的使用 整型&#xff1a;二进制0b100十进制4、八进制0o100十进制64、十进制100、十六进制0x100十进制256浮点型&#xff1a;123.456&#xff0c;1.23456e2字符串型&#xff1a;‘Hello’&#xff0c;“Hello”布尔型&#xff1a;True、False复数型&…

C++算法 —— 动态规划(8)01背包问题

文章目录 1、动规思路简介2、模版题&#xff1a;01背包第一问第二问优化 3、分割等和子集4、目标和5、最后一块石头的重量Ⅱ 背包问题需要读者先明白动态规划是什么&#xff0c;理解动规的思路&#xff0c;并不能给刚接触动规的人学习。所以最好是看了之前的动规博客&#xff0…

【数据结构】排序(2)—冒泡排序 快速排序

目录 一. 冒泡排序 基本思想 代码实现 时间和空间复杂度 稳定性 二. 快速排序 基本思想 代码实现 hoare法 挖坑法 前后指针法 时间和空间复杂度 稳定性 一. 冒泡排序 基本思想 冒泡排序是一种交换排序。两两比较数组元素&#xff0c;如果是逆序(即排列顺序与排序后…

递归与分治算法(1)--经典递归、分治问题

目录 一、递归问题 1、斐波那契数列 2、汉诺塔问题 3、全排列问题 4、整数划分问题 二、递归式求解 1、代入法 2、递归树法 3、主定理法 三、 分治问题 1、二分搜索 2、大整数乘法 一、递归问题 1、斐波那契数列 斐波那契数列不用过多介绍&#xff0c;斐波那契提出…

行高的继承和消除内外边距

行高的继承性 <style>div {font: 12px/1.5 Microsoft yahei;} ​p {font-size: 14px;}</style> <body><div><p>苏丹红事件</p></div> <body> 12px这里没有行高没有写单位&#xff0c;子类继承父类的1.5倍&#xff0c;就是14*…

AndroidStudio精品插件集

官网 项目地址&#xff1a;Github博客地址&#xff1a;Studio 精品插件推荐 使用需知 所有插件在 Android Studio 2022.3.1.18&#xff08;长颈鹿&#xff09;上测试均没有问题&#xff0c;推荐使用此版本Android Studio 2022.3.1.18&#xff08;长颈鹿&#xff09;正式版下…

Django之十二:模板的继承+用户列表

模板的继承 新建layout.html&#xff1a; {% load static %} <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><link rel"stylesheet" href"{% static plugins…

经典网络架构-ResNet

# 引言 深度残差网络的提出是深度学习领域的里程碑事件&#xff0c;它使得网络可以做大做深&#xff0c;现在主流的网络中都有残差结构 # 问题 - ##深度网络的退化 深度网络有一个普遍的问题&#xff1a;随着网络层数的增加&#xff0c;准确率是先增后减的&#xff0c;准确率增…

十四天学会C++之第二天(函数和库)

1. 函数的定义和调用 在C中&#xff0c;函数是组织和结构化代码的关键工具之一。它们允许您将一段代码封装成一个可重复使用的模块&#xff0c;这有助于提高代码的可读性和维护性。 为什么使用函数&#xff1f; 函数在编程中的作用不可小觑。它们有以下几个重要用途&#xf…

【数据结构---排序】很详细的哦

本篇文章介绍数据结构中的几种排序哦~ 文章目录 前言一、排序是什么&#xff1f;二、排序的分类 1.直接插入排序2.希尔排序3.选择排序4.冒泡排序5.快速排序6.归并排序总结 前言 排序在我们的生活当中无处不在&#xff0c;当然&#xff0c;它在计算机程序当中也是一种很重要的操…

【C语言】青蛙跳台阶 —— 详解

一、问题描述 跳台阶_牛客题霸_牛客网 (nowcoder.com) LCR 127. 跳跃训练 - 力扣&#xff08;LeetCode&#xff09; 二、解题思路 1、当 n 1 时&#xff0c;一共只有一级台阶&#xff0c;那么显然青蛙这时就只有一种跳法 2、当 n 2 时&#xff0c;一共有两级台阶&#xff…

你写过的最蠢的代码是?——前端篇

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

LLVM 插桩 LLVM IR PHI指令

今天在进行 LLVM 插桩时&#xff0c;遇到一个神奇的报错 PHI nodes not grouped at top of basic block!%12 phi i32 [ %.pre, %if.then15 ], [ %argc, %maybe_close_fd_mask.exit ], !dbg !381 label %if.end19 PHI nodes not grouped at top of basic block!%18 phi i32 […

线程的状态与转换,组织与控制

进程和线程分析极其相似。见个人博客&#xff1a;进程的状态与转换以及组织方式 1.线程的状态与转换 2.线程的组织与控制 1.线程控制块&#xff08;TCB&#xff09; 2.线程表

运行中的代码,看不太懂的地方,可以实时查看运行值,以做进一步的判断

运行中的代码&#xff0c;看不太懂的地方&#xff0c;可以实时查看运行值&#xff0c;以做进一步的判断 运行中的代码&#xff0c;看不太懂的地方&#xff0c;可以实时查看运行值&#xff0c;以做进一步的判断 运行中的代码&#xff0c;看不太懂的地方&#xff0c;可以实时查看…

OpenCV 14(角点特征Harris和Shi-Tomasi)

一、角点 角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用。角点在三维场景重建运动估计&#xff0c;目标跟踪、目标识别、图像配准与匹配等计算机视觉领域起着非常重要的作用。在现实世界中&#xff0c;角点对应于物体的拐角&#xff0c;道路的十字路口、丁字路…

机器学习 不均衡数据采样方法:imblearn 库的使用

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

【Hello Linux】多路转接之 epoll

本篇博客介绍&#xff1a; 多路转接之epoll 多路转接之epoll 初识epollepoll相关系统调用epoll的工作原理epoll服务器编写成员变量构造函数 循环函数HandlerEvent函数epoll的优缺点 我们学习epoll分为四部分 快速理解部分概念 快速的看一下部分接口讲解epoll的工作原理手写epo…