当前位置: 首页 > news >正文

C++ 类与对象(下):从构造函数到编译器优化深度解析

目录

一、再探构造函数:初始化列表的核心逻辑

1. 初始化列表的基本用法

2. 必须使用初始化列表的场景

3. 成员变量的初始化顺序

4. 成员变量的缺省值(C++11 特性)

5. 初始化列表的核心总结

二、类型转换:内置类型与类类型的双向转换

1. 内置类型隐式转换为类类型

2. 禁止隐式转换:explicit 关键字

3. 类类型之间的隐式转换

三、static 成员:属于类的共享资源

1. 静态成员变量

2. 静态成员函数

3. 静态成员的核心注意事项

四、友元:突破封装的 “特殊通道”

1. 友元函数

2. 友元类

五、内部类:嵌套在类中的独立类

1. 内部类的基本特性

2. 内部类的使用场景

六、匿名对象:临时使用的 “无名称对象”

1. 匿名对象的基本用法

2. 匿名对象的注意事项

七、对象拷贝的编译器优化:提升效率的 “隐形之手”

1. 编译器优化的常见场景

(1)传值传参的优化

(2)传值返回的优化

2. 关闭编译器优化(用于调试)

八、实战案例:日期相关工具的实现

1. 案例 1:计算一年中的第几天

2. 案例 2:计算两个日期的差值

九、总结


在 C++ 面向对象编程中,类与对象是核心概念,而掌握类与对象的进阶知识,是写出高效、健壮代码的关键。本文将从构造函数的深度探索出发,依次讲解类型转换、static 成员、友元、内部类、匿名对象以及对象拷贝的编译器优化,最后结合实际案例巩固知识点,带你全面攻克 C++ 类与对象的进阶内容。

一、再探构造函数:初始化列表的核心逻辑

构造函数是创建对象时自动调用的特殊成员函数,用于初始化对象的成员变量。除了函数体内赋值,初始化列表是更高效、更灵活的初始化方式,尤其在处理特殊成员变量时不可或缺。

1. 初始化列表的基本用法

初始化列表以冒号 : 开头,后续紧跟逗号分隔的成员变量初始化项,每个成员变量后通过括号指定初始值或表达式,语法格式如下:

class 类名 {
public:类名(参数列表) : 成员变量1(初始值1), 成员变量2(初始值2), ... {// 函数体(可选,用于后续逻辑处理)}
private:成员变量1;成员变量2;...
};

例如,定义一个 Date 类,通过初始化列表初始化年份、月份和日期:

class Date {
public:Date(int year, int month, int day) : _year(year), _month(month), _day(day) {// 无额外逻辑,仅初始化}
private:int _year;int _month;int _day;
};

2. 必须使用初始化列表的场景

以下三类成员变量必须在初始化列表中初始化,否则会编译报错:

  • 引用成员变量:引用必须在定义时绑定对象,无法先定义后赋值,初始化列表是唯一的初始化时机。
  • const 成员变量:const 变量一旦定义就不能修改,必须在初始化列表中指定初始值。
  • 无默认构造的类类型成员:若成员变量的类没有默认构造函数(即需要显式传参的构造函数),则必须在初始化列表中通过传参调用其构造函数。

以包含 Time 类成员(无默认构造)、引用成员和 const 成员的 Date 类为例:

class Time {
public:// Time无默认构造,必须传参Time(int hour) : _hour(hour) {}
private:int _hour;
};class Date {
public:// 必须通过初始化列表初始化_t、_ref、_nDate(int& ref, int year, int month, int day, int hour) : _ref(ref), _n(100), _t(hour), _year(year), _month(month), _day(day) {}
private:int _year;int _month;int _day;Time _t;       // 无默认构造的类类型成员int& _ref;     // 引用成员const int _n;  // const成员
};

若未在初始化列表中初始化上述三类成员,编译器会直接报错,例如提示 “必须初始化引用”“const 限定类型对象必须初始化” 等。

3. 成员变量的初始化顺序

初始化列表中成员的声明顺序决定了初始化顺序,与成员在初始化列表中的书写顺序无关。因此,建议将初始化列表的顺序与类内成员声明顺序保持一致,避免逻辑错误。

例如,以下代码中 _a2 先于 _a1 声明,因此 _a2 会先初始化(此时 _a1 未初始化,值为随机值):

class A {
public:A(int a) : _a1(a), _a2(_a1) {}  // 初始化顺序:_a2先初始化,_a1后初始化void Print() {cout << _a1 << " " << _a2 << endl;  // 输出:1 随机值(因_a2初始化时_a1未定义)}
private:int _a2;  // 声明顺序1:_a2先声明int _a1;  // 声明顺序2:_a1后声明
};

4. 成员变量的缺省值(C++11 特性)

C++11 支持在类内成员变量声明时指定缺省值,该缺省值仅作用于 “未在初始化列表中显式初始化” 的成员变量 —— 若成员未在初始化列表中初始化,且声明时有缺省值,则用缺省值初始化;若声明时无缺省值,内置类型成员可能为随机值(取决于编译器),自定义类型成员会调用其默认构造函数(无默认构造则报错)。

class Date {
public:// 仅显式初始化_month,其他成员用缺省值Date() : _month(2) {}void Print() {cout << _year << "-" << _month << "-" << _day << endl;  // 输出:1-2-0(_day为内置类型无缺省值,可能为随机值)}
private:int _year = 1;    // 缺省值1int _month = 1;   // 缺省值1(被初始化列表覆盖为2)int _day;         // 无缺省值(内置类型,值随机)Time _t = 12;     // 缺省值12(调用Time(int hour)构造)const int _n = 10;// 缺省值10(const成员,无需初始化列表显式初始化)
};

5. 初始化列表的核心总结

  • 无论是否显式书写初始化列表,每个构造函数都存在初始化列表,所有成员变量都会通过初始化列表完成初始化。
  • 初始化列表的优先级高于缺省值:显式在初始化列表中初始化的成员,用指定值;未显式初始化的成员,用缺省值(若有);无缺省值的内置类型成员可能为随机值,自定义类型成员需有默认构造。

二、类型转换:内置类型与类类型的双向转换

C++ 支持内置类型与类类型、类类型与类类型之间的隐式转换,但需通过特定构造函数实现;若要禁止隐式转换,可使用 explicit 关键字。

1. 内置类型隐式转换为类类型

当类存在 “仅接收一个内置类型参数” 的构造函数时,C++ 允许将该内置类型值隐式转换为类对象,本质是先创建一个临时类对象,再用临时对象初始化目标对象(编译器会优化为直接构造)。

class A {
public:// 单参数构造函数,支持int隐式转换为AA(int a1) : _a1(a1) {}void Print() { cout << _a1 << endl; }
private:int _a1;
};int main() {A aa1 = 1;  // 隐式转换:int 1 → A(1),编译器优化为直接构造aa1.Print();// 输出:1const A& aa2 = 2;  // 隐式转换:int 2 → 临时A对象,引用绑定临时对象(需const)aa2.Print();       // 输出:2// C++11支持多参数隐式转换(通过初始化列表)A aa3 = {3, 4};    // 隐式转换:{3,4} → A(3,4)(需A有双参数构造函数)return 0;
}

2. 禁止隐式转换:explicit 关键字

在构造函数前添加 explicit 关键字,可禁止内置类型到类类型的隐式转换,仅允许显式构造(即通过 类名(参数) 直接创建对象)。

修改上述 A 类的构造函数:

class A {
public:// explicit禁止隐式转换explicit A(int a1) : _a1(a1) {}...
};int main() {A aa1 = 1;  // 编译报错:禁止隐式转换A aa2(1);   // 显式构造,正确return 0;
}

3. 类类型之间的隐式转换

类类型之间的隐式转换,需目标类存在 “以源类对象为参数” 的构造函数(即转换构造函数)。例如,B 类存在接收 A 对象的构造函数,则 A 对象可隐式转换为 B 对象。

示例代码:

class A {
public:A(int a1) : _a1(a1) {}int GetA1() const { return _a1; }
private:int _a1;
};class B {
public:// 转换构造函数:A → BB(const A& a) : _b(a.GetA1()) {}
private:int _b;
};int main() {A aa(5);B bb = aa;  // 隐式转换:A对象aa → B对象bb(调用B(const A&))const B& rb = aa;  // 引用绑定转换后的临时B对象(需const)return 0;
}

三、static 成员:属于类的共享资源

用 static 修饰的成员变量和成员函数,称为静态成员,其核心特点是 “属于类,而非单个对象”,所有对象共享静态成员,存储在静态区(而非对象的内存空间中)。

1. 静态成员变量

  • 类内声明,类外初始化:静态成员变量需在类内声明(添加 static),在类外(全局作用域)初始化,且初始化时无需加 static,语法为 类型 类名::静态成员变量 = 初始值
  • 共享性:所有对象访问的是同一个静态成员变量,修改一个对象的静态成员,会影响所有对象。
  • 访问方式:可通过 类名::静态成员变量 或 对象.静态成员变量 访问(受访问限定符限制,如 private 静态成员仅类内可访问)。

示例:统计类对象的创建个数

class A {
public:A() { ++_scount; }          // 构造函数:创建对象时计数+1A(const A& t) { ++_scount; } // 拷贝构造:拷贝对象时计数+1~A() { --_scount; }         // 析构函数:销毁对象时计数-1static int GetCount() {     // 静态成员函数:获取计数return _scount;}
private:static int _scount;  // 类内声明:统计对象个数
};// 类外初始化:静态成员变量必须在此处初始化
int A::_scount = 0;int main() {cout << A::GetCount() << endl;  // 输出:0(无对象创建)A a1, a2;                       // 创建2个对象,_scount=2A a3(a1);                       // 拷贝构造1个对象,_scount=3cout << A::GetCount() << endl;  // 输出:3cout << a1.GetCount() << endl;  // 输出:3(对象也可调用静态成员函数)// cout << A::_scount << endl;  // 报错:_scount是private,类外不可访问return 0;
}

2. 静态成员函数

  • 无 this 指针:静态成员函数不属于任何对象,因此没有 this 指针,无法访问非静态成员变量和非静态成员函数(需通过对象或类名访问)。
  • 访问权限:可访问静态成员变量和静态成员函数,受访问限定符限制。
  • 调用方式:与静态成员变量一致,通过 类名::静态成员函数() 或 对象.静态成员函数() 调用。

3. 静态成员的核心注意事项

  • 静态成员变量不能在类内声明时给缺省值:缺省值是给构造函数初始化列表的,而静态成员不属于对象,不走初始化列表。
  • 静态成员函数不能被 const 修饰:const 成员函数的作用是限制 this 指针不可修改,而静态成员函数无 this 指针,无需 const 修饰。

四、友元:突破封装的 “特殊通道”

友元机制允许外部函数或类访问当前类的 private 和 protected 成员,是突破类封装的灵活方式,但会增加类之间的耦合度,需谨慎使用。友元分为友元函数友元类两类。

1. 友元函数

友元函数是在类内通过 friend 声明的外部函数,其核心特点:

  • 友元函数不是类的成员函数,无 this 指针,需通过参数传递类对象才能访问其成员。
  • 友元声明可放在类内任意位置(public/private/protected),不受访问限定符限制。
  • 一个函数可同时是多个类的友元函数。

示例:通过友元函数访问两个类的私有成员

// 前置声明:告诉编译器B是一个类,避免A的友元函数声明报错
class B;class A {// 声明func为A的友元函数friend void func(const A& aa, const B& bb);
private:int _a1 = 1;
};class B {// 声明func为B的友元函数friend void func(const A& aa, const B& bb);
private:int _b1 = 3;
};// 友元函数:可访问A和B的私有成员
void func(const A& aa, const B& bb) {cout << aa._a1 << endl;  // 输出:1(访问A的私有成员)cout << bb._b1 << endl;  // 输出:3(访问B的私有成员)
}int main() {A aa;B bb;func(aa, bb);  // 调用友元函数return 0;
}

2. 友元类

友元类是在类内通过 friend class 类名 声明的外部类,其核心特点:

  • 友元类的所有成员函数都自动成为当前类的友元函数,可访问当前类的私有成员。
  • 友元关系是单向的:若 A 是 B 的友元类,A 的成员可访问 B 的私有成员,但 B 的成员不可访问 A 的私有成员。
  • 友元关系不可传递:若 A 是 B 的友元,B 是 C 的友元,A 不是 C 的友元。

示例:友元类 B 访问 A 的私有成员

class A {// 声明B为A的友元类friend class B;
private:int _a1 = 1;int _a2 = 2;
};class B {
public:void PrintA1(const A& aa) {cout << aa._a1 << endl;  // 输出:1(B的成员函数访问A的私有成员)}void PrintA2(const A& aa) {cout << aa._a2 << endl;  // 输出:2(B的成员函数访问A的私有成员)}
private:int _b1 = 3;
};int main() {A aa;B bb;bb.PrintA1(aa);  // 正确:B是A的友元类bb.PrintA2(aa);  // 正确:B是A的友元类// cout << aa._a1 << endl;  // 报错:_a1是A的私有成员,main函数不可访问return 0;
}

五、内部类:嵌套在类中的独立类

若一个类定义在另一个类的内部,该类称为内部类(嵌套类)。内部类是独立的类,仅受外部类的类域和访问限定符限制,外部类的对象中不包含内部类的成员

1. 内部类的基本特性

  • 默认是外部类的友元:内部类的成员函数可直接访问外部类的 private 和 protected 成员(需通过外部类对象或静态成员访问非静态成员)。
  • 类域限制:内部类的访问需通过 外部类名::内部类名 的方式,例如 A::B b;(创建 A 的内部类 B 的对象)。
  • 封装性:若内部类定义在外部类的 private 区域,则仅外部类可访问该内部类;定义在 public 区域,则外部可访问。

示例:内部类访问外部类的成员

class A {
private:static int _k;  // 外部类的静态私有成员int _h = 1;     // 外部类的非静态私有成员
public:// 内部类B,定义在public区域,外部可访问class B {public:void Print(const A& a) {cout << _k << endl;  // 访问外部类的静态成员(无需对象)cout << a._h << endl; // 访问外部类的非静态成员(需外部类对象)}};
};// 外部类静态成员的类外初始化
int A::_k = 10;int main() {A::B b;  // 通过“外部类名::内部类名”创建内部类对象A a;b.Print(a);  // 输出:10 1(内部类访问外部类成员)cout << sizeof(A) << endl;  // 输出:4(A的大小仅包含_h,不包含B的成员)return 0;
}

2. 内部类的使用场景

当两个类存在紧密关联,且一个类(内部类)的功能仅为另一个类(外部类)服务时,适合使用内部类。例如,Solution 类的 Sum 内部类仅用于计算累加和,无需暴露给外部:

class Solution {// 内部类Sum,定义在private区域,仅Solution可访问class Sum {public:Sum() {_ret += _i;++_i;}};
private:static int _i;static int _ret;
public:int Sum_Solution(int n) {Sum arr[n];  // 创建n个Sum对象,通过构造函数累加1~nreturn _ret;}
};// 静态成员的类外初始化
int Solution::_i = 1;
int Solution::_ret = 0;

六、匿名对象:临时使用的 “无名称对象”

匿名对象是通过 类型(实参) 直接创建的无名称对象,其核心特点是生命周期仅在当前行,使用后立即销毁,适合临时需要一个对象且无需复用的场景。

1. 匿名对象的基本用法

匿名对象的语法格式为 类名(实参),例如 A(1)(创建 A 类的匿名对象,参数为 1)。对比有名对象 A aa(1),匿名对象无需定义对象名,仅在当前行有效。

示例:匿名对象的创建与生命周期

class A {
public:A(int a = 0) : _a(a) {cout << "A(int a):构造对象" << endl;}~A() {cout << "~A():销毁对象" << endl;}
private:int _a;
};int main() {A aa1(1);  // 有名对象:生命周期到main函数结束cout << "创建匿名对象:" << endl;A(2);      // 匿名对象:当前行创建,下一行立即销毁(输出构造+析构)cout << "匿名对象已销毁" << endl;// 匿名对象的实用场景:调用成员函数后立即销毁Solution().Sum_Solution(10);  // 创建Solution匿名对象,调用函数后销毁return 0;
}

运行结果:

A(int a):构造对象  // aa1的构造
创建匿名对象:
A(int a):构造对象  // 匿名对象的构造
~A():销毁对象      // 匿名对象的析构(当前行结束)
匿名对象已销毁
~A():销毁对象      // aa1的析构(main函数结束)

2. 匿名对象的注意事项

  • 匿名对象不能用于 “默认构造的无参场景”:A() 会被编译器识别为函数声明(返回值为 A,无参数),而非匿名对象。若需创建无参匿名对象,可省略括号(仅 C++11 及以后支持),或传递默认参数,例如 A{} 或 A(0)(若 A 的构造函数有默认参数)。

七、对象拷贝的编译器优化:提升效率的 “隐形之手”

现代 C++ 编译器会在不影响代码正确性的前提下,对对象拷贝过程(如传值传参、传值返回)进行优化,减少不必要的拷贝构造,提升程序效率。优化规则虽无统一标准,但主流编译器(如 GCC、VS)的优化逻辑基本一致。

1. 编译器优化的常见场景

(1)传值传参的优化

当通过 “内置类型值” 或 “匿名对象” 传值给函数时,编译器会将 “构造临时对象 + 拷贝构造” 优化为直接构造

示例代码:

class A {
public:A(int a = 0) : _a(a) { cout << "A(int a):构造" << endl; }A(const A& aa) : _a(aa._a) { cout << "A(const A&):拷贝构造" << endl; }
};void f1(A aa) {}  // 传值参数int main() {// 场景1:有名对象传参(无优化,调用拷贝构造)A aa1;f1(aa1);  // 输出:A(const A&):拷贝构造// 场景2:内置类型传参(优化为直接构造)f1(1);    // 输出:A(int a):构造(跳过临时对象的拷贝)// 场景3:匿名对象传参(优化为直接构造)f1(A(2)); // 输出:A(int a):构造(跳过临时对象的拷贝)return 0;
}
(2)传值返回的优化

当函数返回对象时,编译器会根据情况优化:

  • 若返回的是局部对象,且接收返回值的对象在同一表达式中定义,编译器会将 “构造局部对象 + 拷贝构造临时对象 + 拷贝构造接收对象” 优化为直接构造接收对象
  • 若返回后通过赋值运算符赋值给已有对象,则无法优化(需调用赋值重载)。

示例代码:

A f2() {A aa;  // 局部对象return aa;  // 返回局部对象
}int main() {// 场景1:直接接收返回值(优化为直接构造)A aa2 = f2();  // 输出:A(int a):构造(跳过两次拷贝)// 场景2:赋值接收返回值(无优化,调用赋值重载)A aa3;aa3 = f2();    // 输出:A(int a):构造(局部对象)→ A(const A&):拷贝构造(临时对象)→ 赋值重载return 0;
}

2. 关闭编译器优化(用于调试)

在 GCC 编译器中,可通过 -fno-elide-constructors 选项关闭对象拷贝的优化,查看未优化的拷贝过程。例如:

g++ test.cpp -o test -fno-elide-constructors  # 关闭优化
./test  # 运行程序,查看完整的构造、拷贝构造过程

八、实战案例:日期相关工具的实现

结合上述类与对象的知识,我们可以实现实用的日期工具,例如 “计算一年中的第几天” 和 “计算两个日期的差值”。

1. 案例 1:计算一年中的第几天

通过函数封装日期逻辑,判断闰年并计算月份累计天数,最终得到当前日期是当年的第几天。

代码实现:

#include <iostream>
using namespace std;// 获取指定年月的天数(处理闰年2月)
int GetDay(int year, int month) {// 静态数组存储各月天数(索引0无用,对应1~12月)static int MonthDay[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };// 闰年2月为29天if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {return 29;}return MonthDay[month];
}// 计算当前日期是当年的第几天
int Jisuan(int year, int month, int day) {int sum = 0;// 累加前month-1个月的天数for (int i = 1; i < month; i++) {sum += GetDay(year, i);}// 加上当月的天数return sum + day;
}int main() {int year, month, day;// 循环读取输入(直到EOF)while (scanf("%d %d %d", &year, &month, &day) != EOF) {cout << Jisuan(year, month, day) << endl;}return 0;
}

2. 案例 2:计算两个日期的差值

先计算每个日期是当年的第几天,再计算两个年份之间的总天数,最终得到两个日期的差值(包含起始日期,故加 1)。

代码实现:

#include <iostream>
using namespace std;// 复用GetDay函数,获取指定年月的天数
int GetDay(int year, int month) {static int MonthDay[13] = { -1,31,28,31,30,31,30,31,31,30,31,30,31 };if (month == 2 && ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))) {return 29;}return MonthDay[month];
}// 复用Jisuan函数,计算日期是当年的第几天
int Jisuan(int year, int month, int day) {int sum = 0;for (int i = 1; i < month; i++) {sum += GetDay(year, i);}return sum + day;
}int main() {int year1, year2, month1, month2, day1, day2;int sum = 0;// 读取两个日期(格式:YYYYMMDD YYYYMMDD)while (scanf("%4d%2d%2d %4d%2d%2d", &year1, &month1, &day1, &year2, &month2, &day2) != EOF) {int sum1 = Jisuan(year1, month1, day1);  // 日期1的当年天数int sum2 = Jisuan(year2, month2, day2);  // 日期2的当年天数// 计算年份差之间的总天数(假设year1 <= year2)if (year1 < year2) {for (int i = year1; i < year2; i++) {// 闰年366天,平年365天if ((i % 4 == 0 && i % 100 != 0) || (i % 400 == 0)) {sum += 366;} else {sum += 365;}}}// 总差值 = 年份差天数 + (日期2当年天数 - 日期1当年天数) + 1(包含起始日)sum += (sum2 - sum1);cout << sum + 1 << endl;sum = 0;  // 重置sum,准备下一次计算}return 0;
}

九、总结

本文从构造函数的初始化列表切入,系统讲解了 C++ 类与对象的进阶知识,包括类型转换、static 成员、友元、内部类、匿名对象和编译器优化,并通过日期工具案例巩固了知识点。核心要点总结如下:

  1. 初始化列表是特殊成员变量(引用、const、无默认构造类)的唯一初始化方式,初始化顺序取决于成员声明顺序。
  2. 类型转换通过构造函数实现,explicit 可禁止隐式转换,避免意外逻辑。
  3. static 成员属于类,需类外初始化,无 this 指针,适合实现共享资源(如计数器)。
  4. 友元突破封装,但增加耦合度,仅在必要时使用(如跨类访问私有成员)。
  5. 内部类是独立类,默认是外部类的友元,适合实现紧密关联的类逻辑。
  6. 匿名对象生命周期仅一行,适合临时使用,避免不必要的对象命名。
  7. 编译器优化可减少对象拷贝,提升效率,调试时可关闭优化查看完整过程。

掌握这些进阶知识,能帮助你更灵活地设计类结构,写出更高效、更符合 C++ 设计思想的代码。后续可通过更多实战案例,进一步加深对这些知识点的理解和应用。


文章转载自:

http://ewk7X4Jy.dfmjm.cn
http://6X3OzNIZ.dfmjm.cn
http://QUnGiDfk.dfmjm.cn
http://zW2C6ViQ.dfmjm.cn
http://BuGHytq2.dfmjm.cn
http://wZkyWq75.dfmjm.cn
http://MCSl01CG.dfmjm.cn
http://GX0PIyvV.dfmjm.cn
http://Y8wAgd84.dfmjm.cn
http://JnReCpnX.dfmjm.cn
http://8LOnwMSn.dfmjm.cn
http://0JRmBh6s.dfmjm.cn
http://owYUGqZ7.dfmjm.cn
http://GWyWSMUb.dfmjm.cn
http://gF83AfVJ.dfmjm.cn
http://q0dSeCdb.dfmjm.cn
http://q8lrBy2k.dfmjm.cn
http://l8rmPpld.dfmjm.cn
http://0oreNMT1.dfmjm.cn
http://7n8ZT1XA.dfmjm.cn
http://24GRQeNY.dfmjm.cn
http://A7GxxVY9.dfmjm.cn
http://sD7fYOOd.dfmjm.cn
http://D9dZsWbg.dfmjm.cn
http://VdoUxirw.dfmjm.cn
http://DgBIVFcW.dfmjm.cn
http://S5ItWSxf.dfmjm.cn
http://UvfzHJdP.dfmjm.cn
http://fG5pwD3v.dfmjm.cn
http://fY6cJRJJ.dfmjm.cn
http://www.dtcms.com/a/378573.html

相关文章:

  • DNS 域名解析
  • EasyDSS重装系统后启动失败?解决RTMP推流平台EasyDss服务启动失败的详细步骤
  • 自动驾驶中的传感器技术45——Radar(6)
  • 第四章 Elasticsearch索引管理与查询优化
  • 拆分了解HashMap的数据结构
  • Sqlite“无法加载 DLL“e_sqlite3”: 找不到指定的模块”解决方法
  • 项目 PPT 卡壳?模型效果 + 训练数据展示模块直接填 ,451ppt.vip预制PPT也香
  • react-native项目通过华为OBS预签名url实现前端直传
  • Linux-> UDP 编程1
  • Pytest+requests进行接口自动化测试2.0(yaml)
  • 【容器使用】如何使用 docker 和 tar 命令来操作容器镜像
  • 科普:在Windows个人电脑上使用Docker的极简指南
  • 【面试场景题】电商订单系统分库分表方案设计
  • 微服务保护全攻略:从雪崩到 Sentinel 实战
  • springcloud二-Sentinel
  • Redis 持久化与高可用实践(RDB / AOF / Sentinel / Cluster 全解析)
  • Semaphore 信号量深度解析
  • 门店网络重构:告别“打补丁”,用“云网融合”重塑数字竞争力!
  • Linux操作系统之Ubuntu
  • WSL自定义安装多个相同版本的Ubuntu子系统
  • 晶振在5G时代的角色:高精度时钟的核心支撑
  • 【JavaEE】(25) Spring 原理
  • 【科研绘图系列】R语言绘制模型预测与数据可视化
  • 音频中的PDM、PCM概念解读
  • 离线应用开发:Service Worker 与缓存
  • 1、RocketMQ概念详解
  • ZooKeeper Multi-op+乐观锁实战优化:提升分布式Worker节点状态一致性
  • 使用yolo算法对视频进行实时目标跟踪和分割
  • Tomcat日志乱码了怎么处理?
  • 新手该选哪款软件?3ds Max vs Blender深度对比