C++入门篇2

news2024/11/19 8:40:49

文章目录

  • C++入门篇2
    • 1、函数重载
      • 1.1、函数重载概念
      • 1.2、 C++支持函数重载的原理 -- 名字修饰(name Mangling)
    • 2、引用
      • 2.1、引用概念
      • 2.2、引用特性
      • 2.3、常引用
      • 2.4、使用场景
      • 2.5、传值、传引用效率比较
      • 2.6、引用和指针的区别
    • 3、内联函数
      • 3.1、内联函数概念
      • 3.2、内联函数特性
    • 4、auto关键字(C++11)
      • 4.1、auto简介
      • 4.2、auto的使用
      • 4.3、auto不能使用的场景
    • 5、基于范围的for循环(C++11)
      • 5.1、范围for的语法
      • 5.2、范围for的使用条件
    • 6、指针空值nullptr(C++11)

img

C++入门篇2

1、函数重载

1.1、函数重载概念

  • 函数重载是指在同一作用域内使用相同的函数名定义多个函数,这些函数的参数列表(参数的个数或类型)必须不同。函数重载是一种多态的表现形式,常见于面向对象的编程语言如C++和Java。

    #include <iostream>
    
    using namespace std;
    
    int Add(int a, int b) {
        return a + b;
    }
    
    float Add(float a, int b) {
        return a + b;
    }
    
    double Add(double a, int b) {
        return a + b;
    }
    
    int Add(double a, double b) {
        return a + b;
    }
    
    //函数重载
    int main() {
        cout << Add(1, 1) << endl;
        cout << Add(1.1f, 1) << endl; //1.1f数据类型为float
        cout << Add(1.1, 1) << endl;//1.1 默认数据类型为double
        cout << Add(1.1, 1.1) << endl;
        std::cout << "Hello, World!" << std::endl;
        return 0;
    }
    
    

1.2、 C++支持函数重载的原理 – 名字修饰(name Mangling)

为什么C++支持函数重载,而C语言不支持函数重载呢?

在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接

这里我们以gcc编译器和g++编译器来演示C语言和C++的链接规则(过程好演示一点)。

这里涉及到C语言链接的时候是根据符号表去根据函数名去找相应的函数,当一个文件开始运行时,符号表会收集所有的函数名,这里函数名不加修饰,由于是根据函数名来找函数,所以函数名不能重复,不然不知找哪个!

而C++也是有符号表的,但是这个符号表记录的函数名和C语言不一样,这里的函数名会加以修饰,修饰规则是:==_Z+函数长度

+函数名+类型首字母==。

  • 采用C语言的编译后结果

    结论在linux下,采用gcc编译完成后,函数名字的修饰没有发生改变


  • 采用C++语言的编译后结果

    结论在linux下,采用g++编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中

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

2、引用

2.1、引用概念

  • 引用不是新定义一个变量,而是给已存在变量取了一个别名。编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。

  • 语法:类型& 引用变量名(对象名) = 引用实体;

    int main() {
        int a = 1;
        int &b = a;
    
        cout << &b << endl << &a << endl;//地址一样
    
        return 0;
    }
    

    注意:引用类型必须和引用实体是同种类型的。


2.2、引用特性

  • 引用在定义时必须初始化

  • 一个变量可以有多个引用,这些引用可以指向同一个实体,也可以指向不同的实体。

  • 引用一旦引用一个实体,就不能再引用其他实体。

    int main() {
        int a = 1, b = 0;
        int& c = a;
        int& d = a;
        //int& c = b;//报错,一个变量只能引用一个变量
        cout << &a << endl << &c << endl << &d << endl;//地址一样
        return 0;
    }
    

2.3、常引用

  • 除了普通的引用外,C++还提供了常引用。所谓常引用,就是一旦一个常引用被初始化指向一个对象后,它就不能被重新指向另一个对象

  • 引用类型必须和引用实体是同种类型的。但是仅仅是同种类型,还不能保证能够成功引用。如果用一个普通引用类型去引用其对应的非常量类型对象,那么编译器将会报错。我们不可以可以将一个安全的类型(const修饰的类型)交给一个不安全的类型(可被修改的类型)。对于一个非常量引用,它可以引用一个非常量对象,也可以引用一个常量对象。但是对于常量对象,我们不能改变它的值也不能改变它的类型(即权限不能放大,但是权限可以缩小)

    int main() {
        //权限不能放大
        const int a = 10;
        //int &b = a;//报错
        const int &b = a;
        const int &c = b;
    		//c = 1;//报错
      
        //权限可以缩小
        int d = 20;
        const int &e = d;
    
        //可以给常数取别名
        const int &f = 10;
    
        int i = 1;
        double j = i;
        //double &rj = i;
        const double &rj = i;//i先int提升为double,提升后会有一个常变量记录这个提升后的i(i的原始值不变),所以必须使用常量来引用
    
        return 0;
    }
    

2.4、使用场景

  • 做参数:引用的一个常见用途就是在函数中作为参数使用。在函数中,我们可以通过引用来传递参数,而不是直接传递参数的值。这样可以避免数据的复制,提高了效率。

    void Swap(int &a, int &b) {
        int tmp = a;
        a = b;
        b = tmp;
    }
    
    
    int main() {
        int a = 1, b = 3;
        cout << a << " " << b << endl;//1 3
    
        Swap(a, b);
        cout << a << " " << b << endl;//3 1
        return 0;
    }
    
  • 做返回值:与做参数类似,我们也可以使用引用来返回函数的结果。这样可以避免数据的复制,提高了效率。在返回值是大型对象时特别有用。

    int &Add(int a, int b) {
        static int c = a + b;//只初始化一次
        return c;
    }
    
    
    int main() {
        int &ret = Add(1, 2);
        cout << ret << endl;//3
        
        Add(4, 5);
        cout << ret << endl;//3
        return 0;
    }
    
    • 思考一个问题,为什么第二次输出ret的值也是3?因为在Add函数里,变量c是静态变量,第一次调用Add函数的时候它存在静态区(堆区),第二次调用的时候static int c = a + b;不会执行,因为静态变量c只会被初始化一次,那么第二次返回的就是堆区的c,也就还是3

2.5、传值、传引用效率比较

在C++中,传值和传引用都可以用来传递参数给函数,但它们在执行效率和内存使用上有一些不同。

传值是通过复制实参的值给形参,在函数内部,形参是实参的一个副本,改变形参的值不会影响实参。这种方式不会避免对大型对象的复制操作,缺点是会占用额外的内存来存储副本。

传引用是通过将实参的内存地址给形参,在函数内部,形参可以直接访问实参的内存地址。这种方式可以直接访问并修改实参,优点是可以避免对大型对象进行昂贵的复制操作。

在执行效率方面:

  • 传值对于小型对象来说效率较高,因为复制操作相对较快。
  • 传值对于大型对象来说效率较低,因为复制操作需要花费更多的时间和内存。
  • 传引用对于小型对象和大型对象来说效率都较高,因为不需要需要使用额外的内存来存储形参。

在内存使用方面:

  • 传值需要额外内存来存储副本,如果传递的对象很大,会导致内存占用增加。
  • 传引用不需要额外内存来存储副本,但是需要使用指针来访问对象,可能会导致指针错误或者空指针问题。

在实际编程中,选择传值还是传引用取决于具体的情况。如果传递的对象较大或者需要修改对象,使用传引用可以提高效率;如果只是需要传递对象的值而不是修改对象,使用传值可能更加合适。

  • 值和引用的作为函数参数类型的性能比较

    #include <time.h>
    struct A{ int a[10000]; };
    void TestFunc1(A a){}
    void TestFunc2(A& a){}
    void TestRefAndValue()
    {
        A a;
        // 以值作为函数参数
        size_t begin1 = clock();
        for (size_t i = 0; i < 10000; ++i)
            TestFunc1(a);
        size_t end1 = clock();
        // 以引用作为函数参数
        size_t begin2 = clock();
        for (size_t i = 0; i < 10000; ++i)
            TestFunc2(a);
        size_t end2 = clock();
    // 分别计算两个函数运行结束后的时间
        cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
        cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
    }
    
    int main(){
        TestRefAndValue();//传引用效率更高
        return 0;
    }
    
    
  • 值和引用的作为返回值类型的性能比较

    #include <time.h>
    struct A{ int a[10000]; };
    A a;
    // 值返回
    A TestFunc1() { return a;}
    // 引用返回
    A& TestFunc2(){ return a;}
    void TestReturnByRefOrValue()
    {
        // 以值作为函数的返回值类型
        size_t begin1 = clock();
        for (size_t i = 0; i < 100000; ++i)
            TestFunc1();
        size_t end1 = clock();
        // 以引用作为函数的返回值类型
        size_t begin2 = clock();
        for (size_t i = 0; i < 100000; ++i)
            TestFunc2();
        size_t end2 = clock();
        // 计算两个函数运算完成之后的时间
        cout << "TestFunc1 time:" << end1 - begin1 << endl;
        cout << "TestFunc2 time:" << end2 - begin2 << endl;
    }
    
    int main(){
        TestReturnByRefOrValue();//传引用效率更高
        return 0;
    }
    

2.6、引用和指针的区别

传引用不需要对大型对象进行复制操作。因为在C++中,当一个大型对象被传递给函数时,使用引用参数可以提高参数传递的效率。引用并不产生对象的副本,也就是说,在参数传递时,对象不需要被复制。因此,通过引用,函数可以直接访问并修改实参的内存地址,而不需要像传值那样将实参的值复制给形参,也不需要像传指针那样需要使用额外的内存来存储指针。因此,传引用对于大型对象来说可以提高效率。

  • 语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

  • 底层实现上实际是有空间的,因为引用是按照指针方式来实现的。但是我们一般都认为引用是没开空间的!

    int main()
    {
        int a = 10;
        int& ra = a;
        ra = 20;
        int* pa = &a;
        *pa = 20;
        return 0;
    }
    
    • 通过反编译可以对比引用和指针:

  • 引用和指针的不同点:

    1. 基本性质:指针是一个变量,其内部存储的是指向内存存储单元的地址,而引用是原变量的一个别名,它们在内存中占用的存储单元是同一个
    2. 赋值行为:在对引用进行第一次赋值时,起的是绑定作用,即给引用赋予一个新的名字,它和原变量是同一个东西。此后对引用的赋值,将会改变绑定变量的值。而对于指针,每次赋值都是赋给它自身的地址。
    3. 初始化要求:引用在初始化时必须绑定一个已存在的变量,而指针则无需初始化
    4. 空值情况:指针可以为空(NULL),但引用不能为空。
    5. 可修改性:指针的值在初始化后可以修改,而引用在初始化后就不能修改了,即指针一个变量只能引用一个变量。
    6. 级别限制:指针可以有2级或2级以上,但是引用只能有一级。
    7. 安全性:使用引用比使用指针更安全。例如:引用的生命周期与所绑定的对象的生命周期是相同的,因此无需担心内存泄漏问题。
    8. 内存占用:在大多数情况下,指针所占内存为4字节,Linux下是8字节,而64位则不确定,引用所占内存与原变量所占内存大小相同

    总结起来,指针和引用虽然都是C++中重要的概念,但在使用上、功能上有明显的差异。


3、内联函数

3.1、内联函数概念

  • 内联函数是指用inline关键字修饰的函数,或者在类体内定义的成员函数

  • 内联函数在编译时,会被嵌入到每一个调用处,而不是在调用时发生控制转移。这使得内联函数可以消除函数调用时的时间开销,通常用于频繁执行的函数。

    如果在上述函数前增加inline关键字将其改成内联函数,在编译期间编译器会用函数体替换函数的调用。

    如下图:

3.2、内联函数特性

  • 需要注意的是,递归函数不能被定义为内联函数。此外,内联函数一般适合于不存在复杂的结构(如while和switch等)且只有1~5条语句的小函数。如果一个内联函数有多个执行路径(如在if-else结构中),编译器可能会把它视为普通函数

  • 另外,使用内联函数时要注意:内联函数只能先定义后使用;不能对内联函数进行异常的接口声明即内联函数不能声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

    // F.h
    #include <iostream>
    using namespace std;
    inline void f(int i);//声明
    
    // F.cpp
    #include "F.h"
    void f(int i)//定义
    {
     	cout << i << endl;
    }
    
    // main.cpp
    #include "F.h"
    int main()
    {
     	f(10);
     	return 0;
    }
    // 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用
    

4、auto关键字(C++11)

4.1、auto简介

在C++中,auto关键字用于自动类型推断,即让编译器根据变量的使用上下文自动确定其类型。auto在C++11及其后的版本中引入,用于简化代码并减少手动指定变量类型的需求。

使用auto关键字可以使代码更简洁,并可以减少因手动指定类型而产生的错误。例如,假设有一个复杂的表达式或变量,手动指定其类型可能会很麻烦或容易出错。使用auto可以让编译器自动推断出正确的类型

  • auto可以自动识别类型。如下:

    #include <iostream>
    
    int main() {
        int a = 1;
        auto b = &a;
        auto c = a;
        auto d = b;
        std::cout << typeid(a).name() << std::endl << typeid(b).name() << std::endl << typeid(c).name() << std::endl << typeid(d).name() << std::endl;// i Pi i Pi
      	//i表示int ,Pi表示Pointer int,也就是int*
        return 0;
    }
    
  • 但是auto不是用在这么简单的类型上,在后面我们学的越来越多,越来越深后,类型的长度也会有更长的。比如迭代器

    #include <string>
    #include <map>
    
    int main() {
        std::map<std::string, std::string> m{{"apple",  "苹果"},
                                             {"orange", "橙子"},
                                             {"pear",   "梨"}};
        std::map<std::string, std::string>::iterator it = m.begin();
        while (it != m.end()) {
            //....
        }
        return 0;
    }
    
    • 这里的变量it的类型是std::map<std::string, std::string>::iterator,这里我们用auto关键字就会使得代码简单很多。
    #include <string>
    #include <map>
    
    int main() {
        std::map<std::string, std::string> m{{"apple",  "苹果"},
                                             {"orange", "橙子"},
                                             {"pear",   "梨"}};
        auto it = m.begin();
        while (it != m.end()) {
            //....
        }
        return 0;
    }
    
  • 注意:使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

4.2、auto的使用

  • auto与指针和引用结合起来使用

    用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。

    int main() {
        int x = 10;
        auto a = &x;
        auto *b = &x;
        auto &c = x;
        cout << typeid(a).name() << endl;
        cout << typeid(b).name() << endl;
        cout << typeid(c).name() << endl;
        *a = 20;
        *b = 30;
        c = 40;
        return 0;
    }
    
  • 在同一行定义多个变量
    当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

    void TestAuto()
    {
        auto a = 1, b = 2;
        //auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
    }
    

4.3、auto不能使用的场景

  • auto不能作为函数参数

    // 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
    void TestAuto(auto a)
    {
      //考虑一个问题,如果这个函数定义了,但是没调用,那么auto推导的类型是什么?所以肯定不行吧
    }
    
  • auto不能用来声明数组

    void TestAuto() {
        int a[] = {1, 2, 3};
        //auto b[] = {4,5,6};//auto不能用来声明数组
    }
    
  • 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法

  • auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环(基于范围的for循环),还有lambda表达式等进行配合使用。


5、基于范围的for循环(C++11)

5.1、范围for的语法

  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

    for(用于迭代的变量:被迭代的范围){}

    //传统for
    void TestFor1() {
        int array[] = {1, 2, 3, 4, 5};
        for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
            array[i] *= 2;
        for (int *p = array; p < array + sizeof(array) / sizeof(array[0]); ++p)
            cout << *p << endl;
    }
    
    //新型for
    void TestFor2() {
        int array[] = {1, 2, 3, 4, 5};
        for (auto &e: array)
            e *= 2;
        for (auto e: array)
            cout << e << " ";
        return 0;
    }
    

    注意:与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环

5.2、范围for的使用条件

  • for循环迭代的范围必须是确定的
    对于数组而言,就是数组中第一个元素和最后一个元素的范围;对于类而言,应该提供begin和end的方法,begin和end就是for循迭代的范围。

  • 注意:以下代码就有问题,因为for的范围不确定

    void TestFor(int array[]) {
        for (auto &e: array)
            cout << e << endl;
    }
    
  • 迭代的对象要实现++和==的操作,我们看到这里for循环里使用auto &e,在范围for循环中使用auto&可以引用容器或数组中的元素,并对这些元素进行下一步操作。


6、指针空值nullptr(C++11)

  • 简而言之nullptr就是用来解决NULL的在某些方面的不好。

    • NULL有可能被定义为字面常量0,也可能被定义为无类型指针(void*)0的常量。

      void f(int) {
          cout << "f(int)" << endl;
      }
      
      void f(int *) {
          cout << "f(int*)" << endl;
      }
      
      int main() {
          f(0);//输出f(int)
          f(NULL);//输出f(int)
          f((int *) NULL);输出f(int*)
          return 0;
      }
      
    • 但是nullptr就纯纯是无类型指针(void*)0的常量。

      void f(int) {
          cout << "f(int)" << endl;
      }
      
      void f(int *) {
          cout << "f(int*)" << endl;
      }
      
      int main() {
          f(0);//输出f(int)
          f(nullptr);//输出f(int*)
          f((int *) NULL);输出f(int*)
          return 0;
      }
      
  • 注意:

    • 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。

    • 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。

    • 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。


OKOK,C++入门篇2就到这里。如果你对Linux和C++也感兴趣的话,可以看看我的主页哦。下面是我的github主页,里面记录了我的学习代码和leetcode的一些题的题解,有兴趣的可以看看。

Xpccccc的github主页

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

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

相关文章

代码随想录第四十五天|1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

1049. 最后一块石头的重量 题目&#xff1a; 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 x < y。那么…

绿肥红瘦专栏数据的爬取

前言 要想爬专栏&#xff0c;先得爬用户。要想爬用户&#xff0c;三个header参数挡住了去路&#xff1a;x-zst-81&#xff0c;x-zse-93&#xff0c;x-zse-96&#xff0c;经过搜索x-zse-96&#xff0c;定位到设置该字段的位置&#xff1a; 这个t2是固定的值&#xff0c;t0来自于…

Leetcode——字符

520. 检测大写字母 class Solution { public:bool detectCapitalUse(string word) {int big 0, small 0, len word.length();for (int i 0; i < len; i) {if (word[i] > 65 && word[i] < 90) {big;}else {small;}}if (big len || small len) {return tr…

Leetcode—2652.倍数求和【简单】

2023每日刷题&#xff08;四&#xff09; Leetcode—2652.倍数求和 实现代码 int sumOfMultiples(int n){int ans 0;int i 1;for(; i < n; i) {if((i % 3 0) || (i % 5 0) || (i % 7 0)) {ans i;}}return ans; }测试结果 之后我会持续更新&#xff0c;如果喜欢我的文…

计算机服务器中了勒索病毒怎么解决,勒索病毒解密流程,数据恢复

计算机服务器中了勒索病毒是一件非常令人头疼的事情&#xff0c;勒索病毒不仅会加密企业服务器中的数据&#xff0c;还会对企业计算机系统带来损害&#xff0c;严重地影响了企业的正常运转。最近&#xff0c;云天数据恢复中心工程师总结了&#xff0c;今年以来网络上流行的勒索…

非关系型数据库-Redis

一、缓存概念 缓存是为了调节速度不一致的两个或多个不同的物质的速度&#xff0c;在中间对速度较慢的一方起到加速作用&#xff0c;比如CPU的一级、二级缓存是保存了CPU最近经常访问的数据&#xff0c;内存是保存CPU经常访问硬盘的数据&#xff0c;而且硬盘也有大小不一的缓存…

【专题】测试人员为什么需要学会做业务总结?

背景 如何回答以下这个问题的知识支撑&#xff1a;系统的测试重点在哪&#xff0c;难点是什么&#xff0c;怎么攻克&#xff0c;为什么要这样设计&#xff1f;项目交接效率&#xff1f; 同样是做业务测试&#xff0c;为什么有的人是A有的人只能C 二、框架 2.1 测试场景 重点…

2023年中国火焰切割机分类、产业链及市场规模分析[图]

火焰切割机是一种工业设备&#xff0c;用于利用高温火焰对金属材料进行切割和切割加工的过程。这种技术通常在金属切割、切割、焊接和熔化等领域中使用&#xff0c;通过将氧气和燃料混合产生的火焰来加热金属至高温&#xff0c;然后通过氧化反应将金属氧化物吹散&#xff0c;从…

iPhone没有直接记录通话的功能,但有替代方法

本文介绍了在iPhone上记录通话的两种方法&#xff0c;并提供了可用于记录通话的预装软件和第三方软件的提示。 如何使用谷歌语音录制来电 默认的电话应用程序不支持录制电话呼叫。那么&#xff0c;在iPhone上录制实时对话的最简单方法之一是使用支持录制的手机应用程序。一个…

黑豹程序员-架构师学习路线图-百科:开启分布式架构开发先河,让Java戴上全球第一的皇冠-EJB

文章目录 1、EJB的传奇2、什么是 EJB3、从拥抱到抛弃4、最终版EJB3.0 1、EJB的传奇 EJB这项技术其实已经消亡了&#xff0c;但为何我还专门单另拿出来讲呢&#xff1f;原因有三。 第一、EJB是J2EE雄霸全球的功臣&#xff0c;它把我们编程推向了分布式架构开发&#xff0c;为开…

AUTOSAR AP 硬核知识点梳理(2)— 架构详解

一 AUTOSAR 平台逻辑体系结构 图示逻辑体系结构描述了平台是如何组成的,有哪些模块,模块之间的接口是如何工作的。 经典平台具有分层的软件体系结构。定义明确的抽象层,每个抽象层都有精确定义的角色和接口。 对于应用程序,我们需要考虑使用的软件组件,希望它们是可重用的…

TikTok Shop美国本土店VS跨境店,浅析与选择

TikTok不仅仅是一个用于分享有趣短视频的平台&#xff0c;它也逐渐成为了商家们极力推广自己品牌和产品的场所。 在TikTok的商业生态系统中&#xff0c;存在几种不同的商店类型&#xff0c;各有其独特性和适用场景。今天&#xff0c;我们就来深入探讨这些店的差异与特点。 一、…

从0开始在Vscode中搭建Vue2/3项目详细步骤

1.安装node.js:Node.js下载安装及环境配置教程【超详细】_nodejs下载_WHF__的博客-CSDN博客 node.js自带npm&#xff0c;无需单独安装。 验证&#xff1a; node -v npm -v 2.先简单创建一个空文件夹&#xff0c;vscode进入该文件夹&#xff0c;并打开终端。 3.安装cnpm&…

无论有没有按钮,iPhone都可以进行截屏操作!如何在iPhone上截屏

通过简单的按键组合&#xff0c;可以很容易地将iPhone屏幕的图片捕获到图像文件中&#xff0c;并保存到照片库中。以下是操作方法。 什么是屏幕截图 屏幕截图是指通常包含你在设备屏幕上看到的内容的精确副本的图像。在设备内拍摄的数字屏幕截图通常使用相机拍摄物理屏幕的照…

IP协议(下)

目录 一、IP分片 1.为什么需要IP分片 2.IP报头信息 二、分片的组装 1.接收方怎么知道一个报文被分片了 2.同一个报文的分片怎么全部识别出来的 3.报文如何排序&#xff0c;如何得知报文有没有收全 4.怎么将各分片正确组装 5.怎么确定合成的报文是正确的 6.总结 三、…

2023年中国轮胎模具需求量、竞争格局及行业市场规模分析[图]

轮胎模具是轮胎生产线中的硫化成形装备&#xff0c;是高技术含量、高精度及高附加值的个性化模具产品&#xff0c;尤其是轮胎的花纹、图案、字体以及其他外观特征的成形都依赖于轮胎模具&#xff0c;因此其制造技术难度较高。其主要功能是通过所成型材料&#xff08;主要是橡塑…

2023年中国工业空气加热器市场规模及存在问题分析[图]

工业空气加热器行业是指涉及工业领域中空气加热设备的制造、销售、安装和维护的产业。这个行业专注于生产用于加热空气的设备&#xff0c;以满足工业生产过程中的加热需求。工业空气加热器可以采用各种不同的加热技术&#xff0c;如电加热、燃气加热、蒸汽加热等&#xff0c;用…

JAVA IO-转换流

转换流的特点&#xff1a; 1. 其是字符流和字节流之间的桥梁 2. 可对读取到的字节数据经过指定编码转换成字符 3. 可对读取到的字符数据经过指定编码转换成字节字符流和字节流的区别是什么&#xff1f; 字符流字节流编码集&#xff0c; 在实际读取的时候其实字符流还是按照字节…

基于Java的书店仓库管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09; 代码参考数据库参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&am…

SparkStreaming入门

概述 实时/离线 实时&#xff1a;Spark是每个3秒或者5秒更新一下处理后的数据&#xff0c;这个是按照时间切分的伪实时。真正的实时是根据事件触发的数据计算&#xff0c;处理精度达到ms级别。离线&#xff1a;数据是落盘后再处理&#xff0c;一般处理的数据是昨天的数据&…