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

C++:类和对象(上)

文章目录

  • 1 面向过程与面向对象的初步认识
  • 2 类的引入
  • 3 类的定义
  • 4 类的访问限定符及封装
    • 4.1 访问限定符
    • 4.2 封装
  • 5 类的实例化
  • 6 类对象模型
    • 6.1 如何计算类的大小
    • 6.2 类对象的存储方式猜测
  • 7 this指针
    • 7.1 this指针的引出
    • 7.2 this指针的特性
  • 8 C语言和C++栈(Stack)实现的对比


1 面向过程与面向对象的初步认识

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

如下,假设我们需要完成洗衣服的任务,则C语言考虑的就是将洗衣服整个过程分成一个个步骤:

面向过程

C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

如下,同样是洗衣服这件事,可以将其分为四个对象:衣服洗衣粉洗衣机 。整个过程中,人需要将衣服放进洗衣机、倒入洗衣粉、启动洗衣机;洗衣机完成洗衣并甩干。整个过程主要是由人、衣服、洗衣粉、洗衣机四个对象之间的交互完成的,人不需要关注洗衣机具体是如何洗衣服的,是如何甩干的。

面向对象


2 类的引入

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量(兼容C的语法),也可以定义函数。 如:用C语言方式实现的栈,结构体中只能定义变量;而现在以C++方式实现,struct 中还可以定义函数。

C++栈实现部分代码示例:

#include <iostream>using namespace std;typedef int DataType;
struct Stack
{void Init(size_t capacity){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (nullptr == _array){perror("malloc申请空间失败");return;}_capacity = capacity;_size = 0;}void Push(const DataType& data){// 扩容_array[_size] = data;++_size;}DataType Top(){return _array[_size - 1];}void Destroy(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}DataType* _array;size_t _capacity;size_t _size;
};int main()
{Stack s;s.Init(10);s.Push(1);s.Push(2);s.Push(3);cout << s.Top() << endl;s.Destroy();return 0;
}

对于上述示例的结构体定义,在C++中更习惯用 class 来代替,并将其称之为

以定义一个节点类型为例,C中 struct ListNode 是类型,在结构体定义中必须连起来使用;而在C++中,ListNode 就是一个类,在结构体定义中可直接使用。

//C语言中
typedef struct ListNode {
{\kern 8pt}int val;
{\kern 8pt}struct ListNode* next;
}LNode;

//C++中
struct ListNode {
{\kern 8pt}int val;
{\kern 8pt}ListNode* next;
};


3 类的定义

class ClassName{
{\kern 8pt}//类体:由成员函数和成员变量组成
}; //注意后面一定要记得跟分号

其中:

  • class 为定义类的关键字,ClassName 为类的名字,{} 中为类的主体,注意类定义结束时后面的分号不能省略。
  • 类体中的内容称为 类的成员 :类中的 变量 称为 类的属性成员变量 ;类中的 函数 称为 类的方法成员函数。其中类中成员变量与成员函数定义的先后不会影响成员函数的使用。

类的两种定义方式:

  1. 声明和定义全部放在类体中,注意:成员函数如果在类中定义,编译器可能会将其当成内联函数来处理。
    类的定义
  2. 类的声明放在 .h 文件中,成员函数定义放在 .cpp 文件中,注意:成员函数名前面需要加 类名:: ,以提醒编译器该函数不是全局函数,而是某个类中的成员函数。(类定义了一个新的作用域,类的所有成员都在类的作用域中。在类外定义成员时,需要使用域操作符 :: 指明成员属于哪个类域
    示例
    一般情况下,建议使用第二种方式

成员变量命名规则的建议:

示例:

这里我们定义一个日期类,其中包括有初始化成员函数,用于初始化日期(成员变量年、月、日),当我们不注意使初始化成员函数的形参名与类中成员变量同名时,就会产生歧义而无法得到正确结果(函数优先使用自身局部中的变量)。

示例

基于此:推荐在成员变量名前添加 _,如 int _year; 。当然,还有可以用其它方式,一般都是加个前缀或者后缀标识区分就行。


4 类的访问限定符及封装

4.1 访问限定符

访问限定符:

  • public(公有)
  • protected(保护)
  • private(私有)

访问限定符说明:

  1. public 修饰的成员在类外可以直接被访问。
  2. protectedprivate 修饰的成员在类外不能直接被访问。
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。
  4. 如果后面没有访问限定符,访问权限作用域就到}(即类结束)。
  5. class 的默认访问权限为 privatestructpublic(因为struct要兼容C)

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别


关于C++中struct和class的区别:

C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来定义类,和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义类默认的访问权限是private。(在继承和模板参数列表位置,struct和class也有区别)


4.2 封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互,提高了安全性。

C++实现封装的方式:用类将对象的属性(成员变量)和方法(成员函数)结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。

封装本质上是一种管理,让用户更方便使用类。 比如:对于电脑这样一个复杂的设备,提供给用户的就只有开关机键、键盘、显示器、USB插孔等,通过这些让用户和计算机进行交互,完成日常事务,但实际上电脑中真正工作的却是CPU、显卡、内存等一些硬件元件。

示例

对于计算机使用者而言,不用关心内部核心部件(如主板上的线路是如何布局的,CPU内部是如何设计的等),用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此,计算机产商在出厂时,在计算机外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等,让用户可以与计算机进行交互即可。

在C++中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来隐藏对象内部的实现细节,控制哪些方法可以在类外部直接被使用。


5 类的实例化

用类类型创建对象的过程,称为类的实例化。(注意:我们对一个变量的类型及名称的说明即为声明,声明并没有真正的定义了变量,只有为变量开辟了空间才算是真正定义了变量,而对于类,这个定义过程(或者说开辟空间)就叫做类的实例化。)

  • 类是对对象进行描述的,是一个 模型 一样的东西,限定了其中有哪些成员。定义一个类并没有分配实际的内存空间来存储它。(比如人就可以看作一个类,其中描述了人的具体属性(姓名,性别,年龄等)及完成某件事的行为方式等)
  • 个类可以实例化多个对象(就好比多个不同的人个体),实例化出的对象,占用实际的物理空间以存储类成员变量。

int main()
{
{\kern 8pt}Person._age = 100; // 编译失败:error C2059: 语法错误:“.”
{\kern 8pt}return 0;
}

其中Person类是没有空间的,只有Person类实例化出的对象才有具体年龄。(就好比问一个人的年龄,你首先得知道是哪个具体的人)

类的实例化示例:

示例


6 类对象模型

6.1 如何计算类的大小

同样,如下以一个日期类为例:

//日期类
class Date {
public:void Init(int year, int month, int day) {_year = year;_month = month;_day = day;}
private:int _year;//年int _month;//月int _day;//日
};

问题: 类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?该如何计算类的大小?


6.2 类对象的存储方式猜测

  • 猜测一:对象中包含类的各个成员

    对象存储方式1
    缺陷: 每个对象中的成员变量是不同的,但是调用同一份函数(函数的实现是相同的),如果按照此方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。

  • 猜测二:代码只保存一份,在对象中保存存放成员函数代码的地址

    对象存储方式2

  • 猜测三:只保存成员变量,成员函数放在公共代码段

    对象存储方式3

那么对于上述三种存储方式,计算机到底是按哪种方式来存储的?

我们再通过对下面的不同类对象分别获取大小来分析:

//类中既有成员变量,又有成员函数
class A1 {
public:void f1() {}
private:int _a;
};//类中仅有成员函数
class A2 {
public:void f2() {}
};//类中什么都没有---空类
class A3
{};int main() {cout << "A1类的大小:" << sizeof(A1) << endl;cout << "A2类的大小:" << sizeof(A2) << endl;cout << "A3类的大小:" << sizeof(A3) << endl;return 0;
}

测试结果:

测试结果

可以发现: 对于既有成员变量,也有成员函数的A1类,其大小只将成员变量计算在内了,由此可见,对于之前猜测的一、二两种对象存储方式都不符合,只有第三种猜测符合测试结果;而对于只包含成员函数的类或空类,其大小都为一个字节。

结论:一个类的大小,实际就是该类中"成员变量之和",当然并不是单纯的将每个成员变量的大小相加,还要注意内存对齐(具体结构体内存对齐规则可参看:link);注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。(这一个字节不存储有效数据,而是起占位作用,标识对象被实例化定义出来了。)


7 this指针

7.1 this指针的引出

这里还是先定义一个日期类 Date 作为示例:

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(2023, 2, 3);d2.Init(2023, 2, 4);d1.Print();d2.Print();return 0;
}

思考: Date类中有Init和Print两个成员函数,函数体中没有关于对象的区分,那当d1调用Init函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

解释:C++中通过引入 this 指针来解决该问题,即:C++编译器给每个 "非静态的成员函数" 增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有 “成员变量” 的操作,都是通过该指针去访问的。只不过所有的操作对用户是透明的,即用户不需要主动传参,编译器自动完成。


7.2 this指针的特性

  1. this指针的类型:类类型* const ,即成员函数中不能给this指针赋值。

  2. 我们不能显示的在成员函数参数列表中添加this指针,但可以在成员函数内部使用this指针,且this指针只能在 “成员函数” 内部使用。
    示例

  3. this指针本质上是 “成员函数” 的形参, 当对象调用成员函数时,将对象地址作为实参传递给this形参,所以对象中不存储this指针(作为形参,this指针是存在栈中的)。

  4. this指针是 “成员函数” 第一个隐含的指针形参,一般情况由编译器通过 ecx寄存器 自动传递,不需要用户传递。(即不需要我们再在调用函数时进行对象地址的传参)

    this指针


思考:this指针可以为空吗?

我们先来看看如下代码:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A{
public:void Print(){cout << "Print()" << endl;}private:int _a;
};int main(){A* p = nullptr;p->Print();return 0;
}

编译运行结果:编译通过,程序正常运行,成功输出 Print()


再看看接下来这段代码:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A{
public:void PrintA(){cout << _a << endl;}private:int _a;
};int main(){A* p = nullptr;p->PrintA();return 0;
}

编译运行结果:运行崩溃,报错提示访问权限冲突,this指针是空指针。


是什么原因造成了这两种程序运行结果呢?

解释: 从前面对象存储方式的讲解中我们知道了成员函数是存储在公共代码段,当我们使用对象调用函数时(受到类域限制,虽然函数存在公共代码段,但需要使用 对象.成员函数 的方法才能进行调用,不能直接调用成员函数),不需要在对象里面进行查找,只需要在公共代码段中查找,反映在汇编指令上即是通过 call 指令跳转到函数所在地址处。两段代码的区别在于,第一段代码中调用的成员函数中没有用this指针访问对象中成员变量的操作,因此运行函数时,并没有用this指针进行解引用操作,也就不会有访问冲突和空指针异常了;而第二段代码中调用的成员函数中使用this指针进行了解引用来访问对象中的成员变量,而this指针又是空指针,无法进行解引用,因此发生了空指针异常,程序运行崩溃。事实上,我们通过对象指针去访问对象的成员函数时,是否有对this指针进行解引用,不是看有没有解引用符号(-> 或 *),而要看程序运行时是否需要到对象中进行查找,若是需要,则表示有解引用,反之不然。

示例


8 C语言和C++栈(Stack)实现的对比

  1. C语言实现
#include <assert.h>
#include <stdio.h>typedef int DataType;
typedef struct Stack
{DataType* array;int capacity;int size;
}Stack;void StackInit(Stack* ps)
{assert(ps);ps->array = (DataType*)malloc(sizeof(DataType) * 3);if (NULL == ps->array){assert(0);return;}ps->capacity = 3;ps->size = 0;
}void StackDestroy(Stack* ps)
{assert(ps);if (ps->array){free(ps->array);ps->array = NULL;ps->capacity = 0;ps->size = 0;}
}void CheckCapacity(Stack* ps){if (ps->size == ps->capacity){int newcapacity = ps->capacity * 2;DataType* temp = (DataType*)realloc(ps->array,newcapacity * sizeof(DataType));if (temp == NULL){perror("realloc申请空间失败!!!");return;}ps->array = temp;ps->capacity = newcapacity;}
}void StackPush(Stack* ps, DataType data)
{assert(ps);CheckCapacity(ps);ps->array[ps->size] = data;ps->size++;
}int StackEmpty(Stack* ps)
{assert(ps);return 0 == ps->size;
}void StackPop(Stack* ps)
{if (StackEmpty(ps))return;ps->size--;
}DataType StackTop(Stack* ps)
{assert(!StackEmpty(ps));return ps->array[ps->size - 1];
}int StackSize(Stack* ps)
{assert(ps);return ps->size;
}int main()
{Stack s;StackInit(&s);StackPush(&s, 1);StackPush(&s, 2);StackPush(&s, 3);StackPush(&s, 4);printf("%d\n", StackTop(&s));printf("%d\n", StackSize(&s));StackPop(&s);StackPop(&s);printf("%d\n", StackTop(&s));printf("%d\n", StackSize(&s));StackDestroy(&s);return 0;
}

可以看到,在用C语言实现时,Stack相关操作函数有以下共性:

  • 每个函数的第一个参数都是 Stack*
  • 函数中必须要对第一个参数检测,因为该参数可能会为NULL。
  • 函数中都是通过 Stack* 参数操作栈的。
  • 调用时必须传递 Stack 结构体变量的地址。

C语言中结构体只能定义存放数据的结构,操作数据的方法不能放在结构体中,即数据和操作数据的方式是分离开的 ,而且实现上相对复杂一点,涉及到大量的指针操作,稍不注意可能就会出错。


  1. C++实现
#include <iostream>using namespace std;typedef int DataType;
class Stack
{
public:void Init(){_array = (DataType*)malloc(sizeof(DataType) * 3);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = 3;_size = 0;}void Push(DataType data){CheckCapacity();_array[_size] = data;_size++;}void Pop(){if (Empty())return;_size--;}DataType Top() { return _array[_size - 1]; }int Empty() { return 0 == _size; }int Size() { return _size; }void Destroy(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}private:void CheckCapacity(){if (_size == _capacity){int newcapacity = _capacity * 2;DataType* temp = (DataType*)realloc(_array, newcapacity *sizeof(DataType));if (temp == NULL){perror("realloc申请空间失败!!!");return;}_array = temp;_capacity = newcapacity;}}private:DataType* _array;int _capacity;int _size;
};int main()
{Stack s;s.Init();s.Push(1);s.Push(2);s.Push(3);s.Push(4);printf("%d\n", s.Top());printf("%d\n", s.Size());s.Pop();s.Pop();printf("%d\n", s.Top());printf("%d\n", s.Size());s.Destroy();return 0;
}

C++中通过类可以将数据以及操作数据的方法进行有机结合,通过访问权限可以控制哪些方法在类外可以被调用(即封装)。 在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。而且每个方法不需要再传递 Stack* 参数了,编译器编译之后该参数会自动还原,即C++中 Stack* 参数是编译器维护的,C语言中需要用户自己维护。


以上是我对C++中类和对象的一些初步认识,如有错误,希望大家帮忙指正,也欢迎大家给予建议和讨论,谢谢!

相关文章:

C++:类和对象(上)

文章目录1 面向过程与面向对象的初步认识2 类的引入3 类的定义4 类的访问限定符及封装4.1 访问限定符4.2 封装5 类的实例化6 类对象模型6.1 如何计算类的大小6.2 类对象的存储方式猜测7 this指针7.1 this指针的引出7.2 this指针的特性8 C语言和C栈&#xff08;Stack&#xff09…...

数据库 与 数据仓库的本质区别是什么?

当用计算机来处理数据的时候, 数据就需要存储和管理了。早期的数据, 就是用一个文件来实现的, 即是文件系统。随着处理的数据量增大, 发展到用数据库来管理和存储数据了。 数据库包括多媒体数据库、对象关系数据库和关系数据库。关系数据库管理系统,已经成为了事实上通用的数据…...

数据库实践LAB大纲 05 JDBC 连接

概述 Java DataBase Connectivity&#xff0c;Java 数据库连接 执行SQL的Java API 为多种关系型数据提供统一访问 FUNCTION 建立与数据库的连接向数据库发送 SQL 语句处理从数据库返回的结果 四种常见JDBC驱动程序 JDBC-ODBC Bridge drivernative-API, partly Java driver…...

Linux部署nuxt3

最近写了一个项目&#xff0c;需要打包部署&#xff0c;过程还是比较繁琐的&#xff0c;因为需要先配置运行环境。准备采用 pm2 管理项目运行&#xff0c;需要在服务器安装 pm2&#xff0c;而安装 pm2 的话用 npm 命令最方便&#xff0c;所以还要下载 node 环境。那么&#xff…...

鸟哥的Linux私房菜读书笔记:文件系统的简单操作

磁盘与目录的容量 现在我们知道磁盘的整体数据实在superblock区块中,但是每个个别文件的容量则在inode当中记载的. 那在命令行下面该如何显示处这几个数据呢? df:列出文件系统的整体磁盘书用量du:评估文件系统的磁盘使用量(常用在推估目录所占容量)df先来说明一下范例一所输…...

论如何用python自动下载爱的妹子视频~嘿嘿嘿~

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 又到了学Python时刻~ 现在好看的妹子真的太多啦~ 如何一次性把这些好看的视频全保存下来捏&#xff1f; 开发环境: 版 本: python 3.8 编辑器: pycharm 2022.3.2 专业版 requests >>> pip install request…...

传奇GOM引擎配置PAK密码补丁教程

因为我很少接触GOM引擎&#xff0c;所有很晚才知道PAK密码的事情&#xff0c;以前经常在群里或者QQ上有人问站长&#xff0c;说补丁有PAK密码怎么办&#xff0c;我起初不在意&#xff0c;限制发现是一个大问题&#xff0c;好吧&#xff0c;今天借助这篇文章&#xff0c;分享一下…...

邀您参赛!DCIC 2023「科技金融欺诈风险识别」算法赛正在报名中

近年来&#xff0c;跨境赌博、电信网络诈骗、黑产等外部欺诈违法犯罪形势日益严峻&#xff0c;呈现线上化、产业化、团伙化等特征&#xff0c;国家、监管机构及银行自身都高度重视反欺诈治理工作&#xff0c;坚决守护人民群众的财产安全。 为进一步打击外部欺诈违法犯罪行为&am…...

ElasticSearch-学习笔记04【Java客户端操作索引库】

Java后端-学习路线-笔记汇总表【黑马程序员】ElasticSearch-学习笔记01【ElasticSearch基本介绍】【day01】ElasticSearch-学习笔记02【ElasticSearch索引库维护】ElasticSearch-学习笔记03【ElasticSearch集群】ElasticSearch-学习笔记04【Java客户端操作索引库】【day02】Ela…...

低代码开发平台|制造管理-工艺工序搭建指南

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建制造管理-工艺工序。1.2、应用场景先填充工序信息&#xff0c;再设置工艺路线对应的工序&#xff1b;工序信息及工艺路线列表报表展示的是所有工序、工艺路线信息&#xff0c;可进行新增对应数据的操作。2、设置方法2.1、表…...

Window 安装 Docker

1.开启Hyper-v 2.确定后重启 3.双击安装包进行安装 4.安装完后系统重启 5.打开Docker软件提示&#xff1a;按下图操作后重启Docker 6.设置docker镜像仓库 { “experimental”: false, “features”: { “buildkit”: true }, “registry-mirrors”: [ “https://docker.mirr…...

最近很火的一部电视(狂飙)像安欣和高启强这样类型的人,谁更合适做软件测试工程师

狂飙》央视收视率狂飙。央视发布《狂飙》收视成绩&#xff0c;全剧平均收视1.54%&#xff0c;平均收视份额6.99%&#xff0c;单集最高收视率2.20%&#xff0c;单集最高收视份额10.69%&#xff1b;晚间电视剧类节目第一。可以说还部剧为今年开了个好头&#xff0c;一开年就引爆收…...

LSTM已死,Transformer当立(LSTM is dead. Long Live Transformers! ):上

回想一下在Seq2seq模型中,如何使用Attention。这里简要回顾一下【1】介绍的方法2(并以此为基础展开对Transformer的讨论)。 下图中包含一个encoder(左)和一个decoder(右)。对于decoder来说,给定一个输入,得到输出,如何进一步得到context vector 呢? 我们需要根据和…...

今天面试招了个18K的人,从腾讯出来的果然都有两把刷子···

公司前段时间缺人&#xff0c;也面了不少测试&#xff0c;前面一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资在15-20k&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。看简历很多都是4年工作经验&#xff0c;但面试中&#xff0c;不…...

洛谷 P5764 [CQOI2005]新年好

P5764 [CQOI2005]新年好 题目描述 重庆城里有 nnn 个车站&#xff0c;mmm 条双向公路连接其中的某些车站。每两个车站最多用一条公路连接&#xff0c;从任何一个车站出发都可以经过一条或者多条公路到达其他车站&#xff0c;但不同的路径需要花费的时间可能不同。在一条路径上…...

【自然语言处理】主题建模:BERTopic(实战篇)

主题建模&#xff1a;BERTopic&#xff08;实战篇&#xff09;BERTopic 是基于深度学习的一种主题建模方法。201820182018 年底&#xff0c;Devlinetal.Devlin\ et\ al.Devlin et al. 提出了 Bidirectional Encoder Representations from Transformers (BERT)[1]^{[1]}[1]。BER…...

k8s学习笔记

目录 一、安装前准备 二、安装 1、安装kubelet、kubeadm、kubectl 2、使用kubeadm引导集群 1、下载各个机器需要的镜像 2、初始化主节点 3、加入node节点 3、部署dashboard 1、主节点安装 2、设置访问端口 3、创建访问账号 4、令牌访问获取token 三、实战 1、资源创…...

web自动化测试入门篇05——元素定位的配置管理

&#x1f60f;作者简介&#xff1a;博主是一位测试管理者&#xff0c;同时也是一名对外企业兼职讲师。 &#x1f4e1;主页地址&#xff1a;【Austin_zhai】 &#x1f646;目的与景愿&#xff1a;旨在于能帮助更多的测试行业人员提升软硬技能&#xff0c;分享行业相关最新信息。…...

C语言预处理

文章目录 目录 文章目录 前言 一、程序编译的过程 二、编译阶段 1.预处理(*.i&#xff09; 2.编译(*.s) 3.汇编(*.o) 4.链接 总结 前言 提示&#xff1a;使用vs code(gcc编译器)与vs2022来演示c语言的预处理 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面…...

git报错大全,你将要踩的坑我都帮你踩了系列

使用git push -u origin master报下面的错&#xff1a; 使用git push -u origin master报下面的错&#xff1a; Updates were rejected because the remote contains work that you do not have locally&#xff0c;This is usually caused by another repository pushing to …...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

论文笔记——相干体技术在裂缝预测中的应用研究

目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术&#xff1a;基于互相关的相干体技术&#xff08;Correlation&#xff09;第二代相干体技术&#xff1a;基于相似的相干体技术&#xff08;Semblance&#xff09;基于多道相似的相干体…...

【JVM】Java虚拟机(二)——垃圾回收

目录 一、如何判断对象可以回收 &#xff08;一&#xff09;引用计数法 &#xff08;二&#xff09;可达性分析算法 二、垃圾回收算法 &#xff08;一&#xff09;标记清除 &#xff08;二&#xff09;标记整理 &#xff08;三&#xff09;复制 &#xff08;四&#xff…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...