【c++入门】命名空间,缺省参数与函数重载

Alt

🔥个人主页: Quitecoder

🔥专栏:c++笔记仓
Alt

朋友们大家好!本篇内容我们进入一个新的阶段,进入c++的学习!希望我的博客内容能对你有帮助!

目录

  • 1.c++关键字
  • 2.第一个c++代码
  • 3.命名空间
    • 3.1 namespace
    • 3.2命名空间使用
  • 4.c++中的输入输出
  • 5.缺省参数
      • 编译与链接过程
      • 函数与文件的关系
  • 6.函数重载
    • 6.1函数重载的的原理:名字修饰

1.c++关键字

C++总计63个关键字,C语言32个关键字

在这里插入图片描述
C++是一种与C语言紧密相关的编程语言。尽管它继承了C语言的许多特点,但C++引入了面向对象编程等概念,并增加了一些自己的特性和关键字来支持这些特性。比较C++和C语言的关键字,我们可以发现以下特征:

增加的关键字: C++增加了一些关键字来支持面向对象编程(如类、继承、多态等)和模板编程。例如,classpublicprotectedprivatevirtualfriendtemplatetypename等。这些关键字没有在C语言中。

类型增强:C++增加了一些用于类型安全和方便的关键字,如booltruefalseusingnamespace等。

异常处理:为了支持异常处理,C++引入了trycatchthrow等关键字。

新的转换操作符:C++提供了static_castdynamic_castconst_castreinterpret_cast等关键字进行类型转换,这是C语言中所没有的。

增强的存储类说明符:C++引入了mutablethread_local等存储类说明符。

模板编程:为了支持泛型编程,C++增加了templatetypename关键字。

新增运算符:C++还定义了如newdelete等用于动态内存管理的关键字,这些在C中通常通过库函数如malloc和free来实现。

特殊成员函数关键字:C++还有如defaultdelete等关键字,用于特殊成员函数的声明,这样设计是为了提供更好的控制。

C++相比C语言增加的关键字主要围绕面向对象编程、模板编程、异常处理、类型安全和内存管理等方面。这些新增加的特性和关键字使得C++成为一种更复杂但功能更强大的语言,这些目前我们不做过多解释,后期会逐个遇到

2.第一个c++代码

我们来看第一个c++代码:

#include<iostream>
using namespace std;
int main()
{cout<<"hello world"<<endl;return 0;
}

我们逐个来看:

  • #include<iostream>:这串代码是C++程序中的预处理指令,它的作用是告诉预处理器在实际编译之前包含标准输入输出流库iostream。这个库是C++标准库的一部分,为程序提供了输入输出功能,主要通过定义了一些流对象,例如std::cinstd::cout

我们可以发现在C++标准库中,标头文件通常不使用传统的.h后缀。这是C++标准制定时约定的一种风格,用来区分C++标准库的头文件和C风格或其他库的头文件。C语言的标准库头文件和一些旧的C++代码可能仍然使用.h后缀(例如stdio.h),但C++标准库头文件不遵循这一约定

  • using namespace std;: 这行代码是使用命名空间std的声明。std是标准C++库中定义的命名空间,其中包括了诸如cout、cin等通过这条声明,可以直接使用cout而不是std::cout来引用标准输出流对象,这个后面会讲到
  • cout<<"hello world"<<endl;
    • cout是一个输出流对象,用于发送数据到标准输出设备(如屏幕)
    • <<是插入操作符,用于将后面的数据发送到前面指定的流对象(这里是cout)
    • "hello world"是要输出的字符串。
    • endl是一个操控符,用于在输出流中插入一个换行符,然后刷新输出缓冲区,使得输出立即出现在目标设备上。这在某些情况下比简单使用\n换行符更有用,因为它确保了数据的即时输出

简单的分析完后,我们进行讲解

3.命名空间

在C/C++中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的

在C语言中,实际上没有命名空间这一概念,所有的标识符(包括变量名、函数名等)都位于同一个全局命名空间中。因此,当两个不同的库或代码片段中存在同名的标识符时,就会发生命名冲突。以下是一个简单的示例说明这种情况:

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{printf("%d\n", rand);
return 0;
}

编译后后报错:error C2365: “rand”: 重定义;以前的定义是“函数”
在这里插入图片描述

这里存在的问题是,rand 是 <stdlib.h> 中已经定义的一个函数,该函数用于生成伪随机数。然而,在代码中,又定义了一个全局变量 rand 并赋值为10。这导致当在 main 函数中引用 rand 时,实际上引用的是定义的全局变量,而不是标准库中的 rand() 函数。

这正是命名冲突的一个例子:一个是标准库 <stdlib.h> 中的函数 rand(),另一个是用户定义的全局变量 rand。由于C语言中缺乏命名空间机制,这两个同名的实体会发生冲突

C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决

3.1 namespace

命名空间(Namespace)是C++中一种极为重要的特性,用来避免命名冲突,并且组织代码,使其易于维护和扩展。命名空间提供了一个范围,在这个范围内的名字(可以是变量、函数、结构体、类等)是可见的,但在范围外则不是。这允许开发者在不同的命名空间中使用相同的名字,而不会造成冲突。这特别对大型项目或者在集成多个库的时候非常有用

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}中即为命名空间的成员

namespace myrand
{// 命名空间中可以定义变量/函数/类型int rand = 10;int Add(int left, int right){return left + right;}struct Node{struct Node* next;int val;};
}
  • myrand为命名空间的名字
  • 命名空间可以包含变量、函数、结构、类等多种类型的成员。myrand命名空间内定义了一个名为rand的整型变量,并初始化值为10,这样做的好处是可以避免命名冲突

命名空间也可以嵌套定义,例如:

namespace N1
{
int a;
int b;
int Add(int left, int right)
{return left + right;
}namespace N2{int c;int d;int Sub(int left, int right){return left - right;}}
}

同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中

若我们再定义一个命名空间,取名仍为N1,编译器在编译时会将两个命名空间合并

一个命名空间就定义了一个新的作用域,命名空间中的所有内容都局限于该命名空间中

3.2命名空间使用

方法一:加命名空间名称及作用域限定符

首先我们来介绍一个符号::,由两个冒号组成的一个符号叫做域作用限定符

注意,下面代码均在.cpp后缀的文件实现的

例如代码:

#include<stdio.h>
int a = 1;
int main()
{int a = 20;printf("%d\n", a);return 0;
}

这串代码,打印a时,首先会访问局部变量里面的a,如果我们想访问全局变量中的a,则需要使用全局命名空间操作符::来访问全局变量

在这里插入图片描述
::前缀指示编译器查找全局作用域中的a。因此,即使在main函数内部有一个同名的局部变量,使用::a还是可以访问到全局变量a,打印出的值为1

我们也可以访问自定义空间中的变量:

namespace s1 {int a = 1;
}
namespace s2 {int a = 2;
}
int main()
{int a = 20;printf("%d\n", a);printf("%d\n", s1::a);printf("%d\n", s2::a);return 0;
}

命名空间域将a封起来放在全局变量

编译器使用变量时,会进行搜索,首先会搜索局部域,再搜索全局域,我们想访问命名空间域里面的变量,就需要加命名空间名称及作用域限定符

这种特性在C++中非常有用,尤其是当局部变量的名称可能会与全局变量或者在其他命名空间中的变量重名时,可以通过这种方式明确指明想要使用的是哪个作用域中的变量

方法二:使用using将命名空间中某个成员引入

namespace N1
{int a=2;int b=3;
}
using N1::b;
int main()
{printf("%d\n",N1::a);printf("%d\n",b);return 0;
}

这里,N1命名空间包含了两个全局变量a和b,它们的作用域被限制在了N1命名空间内部。这意味着它们不能被直接访问,除非使用其命名空间名作前缀

接下来,通过using声明导入了N1命名空间中的b变量:

using N1::b;

这个声明使得在using声明所在作用域(在这个例子中,是全局作用域)内,可以直接访问b不需要N1::前缀。这种方式对于频繁访问某个命名空间中的特定成员而不想每次都写全命名空间名时非常有用

printf("%d\n", N1::a); // 输出2,通过完全限定名访问N1中的a
printf("%d\n", b);     // 输出3,通过using声明访问N1中的b
  • 对于N1::a的访问,因为没有用using语句声明a,所以需要使用完全限定名N1::a来访问它
  • 对于b,因为前面有using N1::b;声明,所以可以直接访问,不需要命名空间前缀

方法三:使用using namespace 命名空间名称 引入

namespace N1
{int a=2;int b=3;
}
using namespace N1;
int main()
{printf("%d\n",a);printf("%d\n",b);return 0;
}
using namespace N1;

这一语句告诉编译器,接下来的代码中如果遇到某个符号的名称与N1命名空间内的某个成员的名称匹配,就将这个符号解析为该命名空间内的成员,这使得在后续代码中,你可以不使用N1::前缀就直接访问a和b

4.c++中的输入输出

#include<iostream>
using namespace std;
int main()
{cout<<"hello world"<<endl;return 0;
}

再看这串代码

std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中

说明:

  • #include <iostream>这一行告诉编译器包含标准输入输出流库。这个库提供了输入输出的设施,其中就包括了cout, 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std

  • cout是C++标准库中的一个对象,被封装在名为std的命名空间中,这里我们使用using namespace std,使得输出不需要加前缀,如果不用这串代码,则需要指定命名空间

输出格式如下:

#include<iostream>
int main()
{std::cout<<"hello world"<<std::endl;return 0;
}

cout通常用于向标准输出设备,通常是命令行(控制台)输出文本,endl是另一标准库对象,用于插入换行符并刷新输出缓冲区,也属于std命名空间

下面看这串代码:

#include <iostream>
using namespace std;
int main()
{int a;double b;char c;// 可以自动识别变量的类型cin>>a;cin>>b>>c;cout<<a<<endl;cout<<b<<" "<<c<<endl;return 0;
}
  • cin>>a;:这行代码从标准输入接受一个整数,并将其存储在变量a中。cin会根据提供的变量类型自动解释输入数据。我们假设用户输入了一个整数
  • cin>>b>>c;:这行代码首先从标准输入接受一个双精度浮点数,并将其存储在变量b中,接着接受一个字符并存储在c中。这演示了如何通过一个表达式从cin连续读取多个值

在这里插入图片描述

  • 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型
  • <<是流插入运算符,>>是流提取运算符

5.缺省参数

在C++中,缺省参数(也称为默认参数)是函数或方法参数声明中所指定的默认值。如果在调用函数时未提供相应的参数,那么将自动使用这个默认值。这使得函数调用更加灵活

void Func(int a = 0)
{cout<<a<<endl;
}
int main()
{Func();     // 没有传参时,使用参数的默认值Func(10);   // 传参时,使用指定的实参
return 0;
}

这里打印结果为:

0
10

缺省参数有以下类型:

全缺省参数

void Func(int a = 10, int b = 20, int c = 30){cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;}

在这里插入图片描述
注意,这里传参是按照顺序来的,不可以跳过某个参数传参

半缺省参数

void Func(int a, int b = 10, int c = 20){cout<<"a = "<<a<<endl;cout<<"b = "<<b<<endl;cout<<"c = "<<c<<endl;}

半缺省参数必须从右往左依次来给出,不能间隔着给

  //a.hvoid Func(int a = 10);// a.cppvoid Func(int a = 20){}

注意:如果生命与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值

在C++中,当一个函数有缺省参数(默认参数)时,这个规则确保了程序的清晰性与一致性,避免了潜在的混淆。缺省参数意味着在函数调用中,如果没有提供某些参数,那么将自动使用这些参数的默认值。这句话的含义是,对于给定的函数,其缺省参数应该只在函数声明或定义中的一处指定,而不是两处同时指定

理解这句话的关键在于区分声明定义的概念:

  • 函数声明告诉编译器函数的名称、返回类型以及参数列表(类型、顺序和数量),但不涉及函数的具体实现。函数声明经常出现在头文件(.h)中

  • 函数定义:提供了函数的实际实现,它包括函数的主体,即函数被调用时将执行的具体代码。函数定义包含了函数声明的所有信息,并加上了函数体

为什么不能同时出现

如果在函数的声明和定义中都指定了缺省参数,可能会导致不一致性,使得理解和维护代码变得更加困难,编译器也可能不确定应该使用哪个版本的默认值,尤其是当声明和定义位于不同的文件时,为了避免这种情况,C++标准规定了缺省参数应当只在一个地方指定:

  • 如果函数声明在头文件中进行,那么就在头文件中的声明处指定缺省参数
  • 如果函数没有在头文件中声明(例如,完全在一个.cpp文件内定义),那么就在函数定义处指定缺省参数

最佳实践

最佳实践是在函数的声明中指定缺省参数,而在函数的定义中则省略这些默认值

// 函数声明,在头文件中
void example(int a, float b = 3.14); // 函数定义,在源文件中
void example(int a, float b) {// 函数体
}

在这个例子中,example函数的缺省参数只在函数声明中给出,而在定义时省略了默认值。这符合C++的最佳实践

当函数声明在头文件中进行,并在头文件中指定缺省参数,这与头文件的工作原理及C++编译过程有关

当函数声明在头文件中进行,并在头文件中指定缺省参数,这与头文件的工作原理及C++编译过程有关:

  • 预处理阶段:在这个阶段,编译器处理源代码中的预处理指令,如#include(将头文件内容展开至引用位置)、#define等。如果在头文件中指定了缺省参数,当进行#include预处理时,这些默认值也会被一并复制到每个包含了该头文件的源文件中,这确保了源文件在进入编译阶段时已经拥有了完整的函数声明信息

  • 编译阶段:编译器将预处理后的源代码转换成目标代码(通常是机器代码的一种中间形态)。如果函数的缺省参数在头文件中被声明,那么每个包含了该头文件的源文件都能正确地编译函数调用,因为它们都"看到"了相同的带有缺省参数的函数声明

  • 链接阶段:链接器将多个对象文件(目标代码)和库一起链接成最终的可执行文件。由于缺省参数已经在头文件中声明,并且该头文件被所有需要的源文件正确地包含,链接器不需要关心默认值的问题,因为这些默认值不影响函数的链接过程

我们这里扩展一下:

假如我现在有三个文件,stack.h包含函数的声明,stack.c包含函数的定义,test.c是一个测试函数所用的文件,先简单说明一下这些文件的作用:

  • stack.h(头文件):包含函数声明(也可能包含类型定义、宏定义等)。它的主要目的是提供一个接口的定义,以便其他文件在使用这些函数时,编译器能够了解到它们的存在及其接口
  • stack.c(源文件):包含函数的具体实现。这里编写了在stack.h中声明的函数的代码体
  • test.c(源文件):用于测试的代码文件,它会使用stack.h中声明的函数

编译与链接过程

  1. 预处理:对于每个.c文件,编译过程从预处理开始。预处理器会处理以#开头的指令,例如#include "stack.h"会将stack.h中的内容文本上粘贴到stack.ctest.c文件中,这样stack.ctest.c就可以看到这些函数声明了

  2. 编译:编译器接着编译每个.c源文件,将它们转换成目标代码(通常是机器代码的一种中间形态,称为目标文件,扩展名为.o.obj)。此时,编译器确保源代码符合语法规则,对每个源文件进行类型检查,确保所有函数调用都符合其声明但还不解决跨文件的函数引用问题。例如,stack.c被编译成stack.otest.c被编译成test.o

  3. 链接:一旦所有的源文件被编译成目标文件,链接器(linker)负责将这些目标文件以及必要的库文件链接成一个单一的可执行文件。在链接过程中,如果test.c(对应的是test.o)调用了stack.c中(对应的是stack.o)的函数,链接器负责“修补”这些调用,使得test.o中的调用可以正确地连接到stack.o中定义的函数上,链接器确保所有外部引用都能正确解析到它们所引用的实体。

函数与文件的关系

  • stack.h中声明的函数,让其他源文件知道这些函数的存在、它们的参数以及返回值类型。stack.h扮演了接口的角色。
  • stack.c提供了stack.h中声明的函数的具体实现。test.c作为使用这些函数的客户端代码,通过#include "stack.h"能够调用这些函数。
  • 编译过程中,test.cstack.c分别被编译成中间的目标文件。这些目标文件中的函数调用尚未解析到具体的地址
  • 在链接过程,链接器解析这些调用,使得从test.o中的调用可以正确地定位到stack.o中的函数定义,从而生成一个完整的可执行文件,所有的函数调用都被正确地解析和连接,这个地址修正的过程也叫做重定位

接下来我们所讲解的函数重载与上述内容也有所关联

6.函数重载

函数重载是C++语言的一个特性,它允许在同一作用域内声明几个具有相同名字的函数,只要这些函数的参数列表不同。这个机制让程序员可以为执行类似操作但需要处理不同数据类型或参数数量的函数提供统一的接口

参数不同

#include <iostream>
using namespace std;
void print(int i) {cout << "Printing int: " << i << endl;
}void print(double f) {cout << "Printing float: " << f << endl;
}int main() {print(1);             // 调用 print(int)print(3.14);          // 调用 print(double)return 0;
}

参数个数不同

void f()
{cout << "f()" << endl;
}
void f(int a)
{cout << "f(int a)" << endl;
}

参数顺序不同

void f(int a, char b)
{cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{cout << "f(char b, int a)" << endl;
}

6.1函数重载的的原理:名字修饰

C++支持函数重载的原理,在很大程度上依赖于一种被称为**名字修饰(Name Mangling)**的过程。这种机制使得编译器能够区分同名但参数列表不同的函数,从而支持函数重载

名字修饰是什么?

名字修饰是编译器自动进行的一种处理过程,它将C++源代码中的函数名和变量名转换成包含更多信息的唯一标识符。这些信息通常包括函数的参数类型、参数数量等,甚至可能包括所属的类名(对于类成员函数),通过这种方式,每个重载的函数都会被赋予一个独一无二的名字,确保链接器在最后链接程序的时候能够区分它们

C++中允许函数重载,也就是允许同一个作用域内存在多个同名函数,只要它们的参数列表不同。但在编译成目标代码后,所有的函数名和变量名都必须区分开来,确保每个函数调用都能显式地映射到正确的函数体上。名字修饰通过在函数名中编码函数参数类型等信息,实现了这一点

名字修饰实例

比如,考虑下面的C++函数重载:

void print(int i);
void print(double d);

在经过编译器处理后,这些函数可能会分别被修饰为(名字修饰的具体结果依赖于编译器):

  • print(int) 可能被修饰为 _print_i
  • print(double) 可能被修饰为 _print_d

这样,尽管这两个函数原名相同,但在编译器处理后它们获得了不同的名字,使得编译后的代码中对这些函数的引用能够清晰地区分开来

名字修饰使得C++能够有效地支持函数重载和模板等功能,虽然这种机制在编程过程中对程序员是透明的,但理解其背后的原理对于深入掌握C++语言是有帮助的。同时,这也是C++与其他语言例如C的一个重要区别:C语言不支持函数重载,部分原因就在于它没有采用类似的名字修饰机制

我们来看linux环境下不同编译器编译相同代码的结果:

采用C语言编译器编译后结果
在这里插入图片描述
在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变

采用C++编译器编译后结果
在这里插入图片描述
在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中

通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载
如果两个函数函数名和参数是一样的,返回值不同是不构成重载的,因为调用时编译器没办法区分

本节内容到此结束,感谢大家阅读!!

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

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

相关文章

CTF-辨别细菌

题目描述&#xff1a;try your best to find the flag. 进入靶场后发现是一个游戏&#xff0c;需要全部答对才可以得到最后的flag 查看了一下源码&#xff0c;发现有一个答案模板的模块 尝试解释一下代码 <!-- 答案模版 --> <script id"template_game_pi…

数据结构/C++:红黑树

数据结构/C&#xff1a;红黑树 概念实现基本结构插入uncle为红色节点uncle为黑色节点 总代码展示 概念 红黑树是一种二叉搜索树&#xff0c;一般的二叉搜索会发生不平衡现象&#xff0c;导致搜索效率下降&#xff0c;于是学者们开始探索如何让二叉搜索树保持平衡&#xff0c;这…

Agent驱动的RPA——实在Agent(智能体):自动化时代的新引擎

随着人工智能和机器学习技术的快速发展&#xff0c;智能Agent在 RPA领域扮演了革命性的角色。 Agent驱动的RPA不仅实现了传统规则导向自动化工具的功能升级&#xff0c;而且通过引入自主、智能决策与协作能力&#xff0c;为现代企业带来了更高程度的灵活性与智能化水平。随着数…

【python】(03)初识生成器Generator

系列文章回顾 【python】(01)初识装饰器Decorator 【python】(02)初识迭代器Iterator 【python】(03)初识生成器Generator 文章目录 一.生成器的定义二.生成器的作用三.实际代码示例四.常见问题生成器在 Python 中是非常强大和灵活的工具,可以帮助我们高效地处理大型数据集合或…

C. Lexicographically Largest - 思维

题面 分析 如果没有相同的数那么一定是从最后一个开始向前一个个放入集合&#xff0c;这样不会损失&#xff0c;一旦有相同的&#xff0c;从右向左依次放入&#xff0c;那么一旦遇到集合里已经有的元素&#xff0c;此时最优策略就是将当前这个数减一再放进去&#xff0c;那么…

tensorflow中显存分配

tensorflow中显存分配 问题&#xff1a;使用tensorflow-gpu训练模型&#xff0c;GPU的显存都是占满的。 # GPU 1的显存将占满 os.environ["CUDA_VISIBLE_DEVICES"] "1" 原因&#xff1a;默认情况下&#xff0c;tensorflow会把可用的显存全部占光&#…

第1章 计算机系统概述

王道学习 1.1 操作系统的基本概念 1.1.1 操作系统的概念 1.1.2 操作系统的特征 操作系统是一种系统软件&#xff0c;但与其他系统软件和应用软件有很大的不同&#xff0c;它有自己的特殊性即基本特征。操作系统的基本特征包括并发、共享、虚拟和异步。这些概念对理解和掌握…

网站打开慢有哪些原因造成的?该如何优化

网站打开慢可能有多种原因造成&#xff0c;以下是一些常见的导致网站打开慢的原因以及对应的优化方法&#xff1a; 服务器性能不足&#xff1a; 优化方法&#xff1a; 升级服务器配置、使用CDN加速、优化服务器软件和设置、减少服务器负载等。 大量图片和多媒体文件&#xff1…

python中的面向对象特性

面向对象编程&#xff08;Object-Oriented Programming&#xff0c;简称OOP&#xff09;是一种编程范式&#xff0c;它使用“对象”来设计软件。面向对象编程的主要特性包括封装、继承、多态性和抽象。这些特性使得OOP特别适合处理大型、复杂的软件系统。 特性 1. 封装&#…

kail linux破解密码--- 详细过程(配合图文让你看了就会)

1.准备工作 1.vmware虚拟机 2.kali的系统 3.无线网卡一张(这个是必须的我买的是30多块) 4.这里为了实验&#xff0c;和直观的看到效果&#xff0c;用手机开了一个wifi然后使用kali进行破解 2.下载kali然后安装到虚拟机vmware 直接在官网下载 Get Kali | Kali Linux 我选…

WebXR实践——利用aframe框架浏览器展示全景图片

一、效果 话不多说&#xff0c;先上效果 二、代码 index.html <!DOCTYPE html> <html><head><meta charset"utf-8"><title>360&deg; Image</title><meta name"description" content"360&deg; Imag…

面试算法-64-零钱兑换

题目 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。 你可以认为每种硬币的数量是无限的…

【机器学习】深入解析线性回归模型

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;机器学习 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

高精度铸铁平台制造工艺有多精细——河北北重机械

高精度铸铁平台制造工艺通常包括以下几个步骤&#xff1a; 材料准备&#xff1a;选择合适的铸铁材料&#xff0c;并确保其质量符合要求。常用的铸铁材料包括灰铸铁、球墨铸铁等。 模具制造&#xff1a;根据平台的设计要求&#xff0c;制造适用的模具。模具一般由砂型、金属模具…

【python】flask基于cookie和session来实现会话控制

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

js数组去重常见方法

简单数组 1、使用filter()方法&#xff1a;通过filter()方法遍历数组&#xff0c;返回仅包含首次出现的元素的新数组。 const arr [1, 2, 3, 4, 2, 3, 5]; const list arr.filter((item, index) > arr.indexOf(item) index); console.log(list); // [1, 2, 3, 4, 5]2、…

【开源-土拨鼠充电系统】鸿蒙 HarmonyOS 4.0 App+微信小程序+云平台

✨本人自己开发的开源项目&#xff1a;土拨鼠充电系统 ✨踩坑不易&#xff0c;还希望各位大佬支持一下&#xff0c;在Gitee或GitHub给我点个 Start ⭐⭐&#x1f44d;&#x1f44d; ✍Gitee开源项目地址&#x1f449;&#xff1a;https://gitee.com/cheinlu/groundhog-charging…

力扣Lc19--- 268. 丢失的数字(java版)-2024年3月20日

1.题目描述 2.知识点 &#xff08;1&#xff09;比如数组里面有n个数&#xff0c;然后计算这n个数的总和(用等差求和数列计算&#xff09;,然后减去数组的和&#xff0c;用总和减去数组和即为所得 &#xff08;2&#xff09;加强型 for 循环&#xff08;也称为 for-each 循环&…

spring boot切面execution表达式添加多个包路径

问题描述 在Spring Boot中&#xff0c;如果你想为多个包中的方法创建一个切面&#xff0c;你可以在Pointcut注解中使用||操作符来指定多个包。 解决方案&#xff1a; // 定义切入点为两个包中的任意方法 Pointcut("execution(* com.example.package1..*.*(..)) || execu…

Leetcode 459:重复的子字符串

给定一个非空的字符串 s &#xff0c;检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例 2: 输入: s "aba" 输出: false示例 3: 输入: s "abcabcabcabc&quo…