• 【C++】C++入门


    🎇C++学习历程:入门


    • 博客主页:黎小姐的猫
    • 持续分享博主的C++学习历程
    • 博主的能力有限,出现错误希望大家不吝赐教
    • 分享给大家一句我很喜欢的话: 也许你现在做的事情,暂时看不到成果,但不要忘记,树🌿成长之前也要扎根,也要在漫长的时光🌞中沉淀养分。静下来想一想,哪有这么多的天赋异禀,那些让你羡慕的优秀的人也都曾默默地翻山越岭🐾。

    在这里插入图片描述


    🌹前言

    C++

    • C++是一种面向对象的计算机程序设计语言(C语言是面向过程的),最初它被称作“C with Classes”(包含类的C语言)。
    • C++它是一种静态数据类型检查的、支持多重编程范式的通用程序设计语言,支持过程化程序设计、数据抽象、面向对象程序设计、泛型程序设计等多种程序设计风格。
    • C++是C语言的继承,进一步扩充和完善了C语言,成为一种面向对象的程序设计语言

    🌹1. C++关键字

    C++总计63个关键字,C语言32个关键字
    请添加图片描述


    🌹2. 命名空间

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

    请添加图片描述

    🌷2.1 命名空间的定义

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

    例子:
    在这里插入图片描述

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


    🌷2.2 命名空间的使用

    C++为了防止命名冲突,把自己库里面的东西都定义在一个std的命名空间中

    要使用标准库里面的东西,有三种方式:

    • 第一种:加命名空间名称及作用域限定符

    ::在C++中叫做作用域限定符,我们通过“命名空间名称::命名空间成员”便可以访问到命名空间中相应的成员。

    在这里插入图片描述

    • 第二种:使用using将命名空间中某个成员引入

    在这里插入图片描述

    • 第三种: 使用using namespace 命名空间名称 引入

    请添加图片描述


    🌹3. C++输入和输出

    1. 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名,空间使用方法使用std。
    2. cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
    3. <<是流插入运算符,>>是流提取运算符。
    4. 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型

    例如:

    #include
    //std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
    using namespace std;
    
    int main()
    {
        int a = 1;
        float b = 2.1;
        double c= 2.111;
        char arr[10] = { 0 };
        char d[] = "hello world";
        cin >> arr;
        cout << arr << endl;//endl相当于换行 -> /n
        cout << a << endl;//C++的输入输出可以自动识别变量类型
        cout << b << endl;
        cout << c << endl;
        cout << d << endl;
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    请添加图片描述


    🌹4. 缺省参数

    🌷4.1 缺省参数的概念

    缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参。

    这儿的0就相当于缺省参数,如果实参什么都没传过来,缺省参数就赋值给a,相当于备胎的意思。(没轮胎用的时候才会考虑备胎)
    void Func(int a = 0)
    {
    	cout<<a<<endl;
    }
    int main()
    {
    	Func(); // 没有传参时,使用参数的默认值
    	Func(10); // 传参时,使用指定的实参
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    🌷4.2 缺省参数的分类

    • 全缺省
    //全缺省参数,即函数的全部形参都设置为缺省参数。
    void testFunc2(int a = 10, int b = 20, int c = 30)
    {
    	cout << "a = " << a << endl;
    	cout << "b = " << b << endl;
    	cout << "c = " << c << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 半缺省
    void Func1(int a, int b = 10, int c = 20)//
    {
    	cout << "a = " << a << endl;
    	cout << "b = " << b << endl;
    	cout << "c = " << c << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    缺省参数注意事项:

    • 半缺省参数必须从右往左依次来给出,不能间隔着给
    • 缺省参数不能在函数声明和定义中同时出现 (如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。)
    • 缺省值必须是常量或者全局变量

    🌹5. 函数重载

    🌷5.1 函数重载的概念

    函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题

    using namespace std;
    
    int Add(int x, int y)
    {
        return x + y;
    }
    
    double Add(double x, double y)
    {
        return x + y;
    }
    int main()
    {
        cout << Add(0,1) << endl;//打印0+1的结果
        cout << Add(1.1,2.2) << endl;//打印1.1+2.2的结果
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如果只是返回值不同,则不构成函数重载

    short Add(short left, short right)
    {
        return left+right;
    }
    int Add(short left, short right)
    {
        return left+right;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    请添加图片描述


    🌷5.2 C++支持函数重载的原理

    为什么C++支持函数重载,而C语言不支持函数重载呢?在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接。

    编译过程:
    在这里插入图片描述
    在这里插入图片描述

    • 采用C语言编译器

    在这里插入图片描述

    • 采用C++编译器

    在这里插入图片描述

    • 通过这里就理解了C语言没办法支持重载,因为同名函数没办法区分。而C++是通过函数修饰规则来区分,只要参数不同,修饰出来的名字就不一样,就支持了重载。
    • 在gcc下的修饰规则是:【_Z+函数长度+函数名+类型首字母】。

    🌷5.3 extern “C”

    有时候在C++工程中可能需要将某些函数按照C的风格来编译,在函数前加extern “C”,意思是告诉编译器,将该函数按照C语言规则来编译,所以这个函数不能进行重载。

    例子:

    extern "C" int Add(int left, int right);
    int main()
    {
    	Add(1, 2);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    🌹6. 引用

    🌷6.1 引用的概念

    • 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
    • 类型& 引用变量名(对象名) = 引用实体
    • 引用类型必须和引用实体是同种类型的

    例子:

    #include
    using namespace std;
    
    int main()
    {
        int a = 1;
        int&b = a; //相当于给a起了一个别名为b,int是b的类型
        cout << a << endl;
        cout << b << endl;
        b = 100;  //改变b也就相当于改变了a
        cout << b << endl;
        cout << a << endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述


    🌷6.2 引用的特性

    • 引用在定义时必须初始化
    • 一个变量可以有多个引用
    • 引用一旦引用一个实体,再不能引用其他实体

    在这里插入图片描述


    🌷6.3 常引用

    void TestConstRef()
    {
        //常引用是创建一个临时变量,引用名是临时变量的引用
        const int a = 10;
        //int& ra = a; // 该语句编译时会出错,a为常量,而且a为不可以修改
        const int& ra = a;
        // int& b = 10; // 该语句编译时会出错,b为常量
        const int& b = 10;
        double d = 12.34;
        //int& rd = d; // 该语句编译时会出错,类型不同
        const int& rd = d;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    这里的a,b,d都是常量,常量是不可以被修改的,但是如果你用int&ra等这样来引用a的话,那么引用的这个a是可以被修改的,因此会出问题。

    我们再来看一个例子:

    #include
    using namespace std;
    int main()
    {
    	int a = 10;
    	double&ra = a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    这里涉及了隐士类型提升的问题,在这里int到double存在隐士类型的提升,而在提升的过程中系统会创建一个常量区来存放a类型提升后的结果。因此到这儿,这段代码一看就是错了,因为你隐士类型提升时a是存放在常量区中的,常量区是不可以被修改的,而你用double&ra去引用他,ra这个引用是可以被修改的。

    在这里插入图片描述

    注意:将不可修改的量用可读可写的量来引用是不可以的,但是反过来是可以的,将可读可写的量用只可读的量来引用是可以的。


    🌷6.4 使用场景

    • 做参数:

    用交换函数来举例,我们学习了引用,可以不用指针作为形参了。因为在这里a和b是传入实参的引用,我们将a和b的值交换,就相当于将传入的两个实参交换了。

    void Swap2(int& a, int& b) //通过引用来交换
    {
        int tmp = a;
        a = b;
        b = tmp;
    }
    void Swap1(int* a, int *b) //通过指针来交换
    {
        int tmp = *a;
        *a = *b;
        *b = tmp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 做返回值:
    int& Count()
    {
    	static int n = 0;//留一个问题,为什么要加static
    	n++;
    	// ...
    	return n;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    看一个做返回值的例子:注意看结果
    在这里插入图片描述

    函数调用会开辟栈桢,所以Add(1,2)在调用完以后就被销毁了

    在这里插入图片描述

    注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。


    🌷6.5 传值、传引用效率比较

    以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。


    🌷6.6 引用和指针的区别

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

    int main()
    {
         int a = 10;
         int& ra = a;
         cout<<"&a = "<<&a<<endl;
         cout<<"&ra = "<<&ra<<endl;
         return 0;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

    int main()
    {
         int a = 10;
         
         int& ra = a;
         ra = 20;
         
         int* pa = &a;
         *pa = 20;
         
         return 0;
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    我们来看下引用和指针的汇编代码对比:
    在这里插入图片描述

    引用和指针的区别:

    1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
    2. 引用在定义时必须初始化,指针没有要求
    3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
    4. 没有NULL引用,但有NULL指针
      5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
    5. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
    6. 有多级指针,但是没有多级引用
    7. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
    8. 引用比指针使用起来相对更安全

    🌹7. 内联函数

    🌷7.1 内联函数的概念

    以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。(与宏类似)

    在这里插入图片描述

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

    在这里插入图片描述


    🌷7.2 内联函数的特性

    • inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
    • inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内代码比较长/递归等等,编译器优化时会忽略掉内联。
    • inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到
    // F.h
    #include 
    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 中被引用
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    宏和内联有一定的相似性
    宏的优缺点:

    • 优点:
      1.增强代码的复用性
      2.提高性能
    • 缺点:
      1.不方便调试宏。(因为预编译阶段进行了替换)
      2.导致代码可读性差,可维护性差,容易误用
      3.没有类型安全的检查 。

    C++有哪些技术替代宏?

    1. 常量定义 换用const enum
    2. 短小函数定义 换用内联函数

    🌹8. auto关键字(C++11)

    🌷8.1 auto关键字的概念

    • 在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,但遗憾的是一直没有人去使用它,大家可思考下为什么?
    • C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
    #include
    using namespace std;
    int TestAuto()
    {
    	return 10;
    }
    int main()
    {
    	int a = 10;
    	auto b = a;
    	auto c = 'a';
    	auto d = TestAuto();
    
    	cout << typeid(b).name() << endl; //这个地方要学到后面类的时候才可以解释,这里打印出的是类型名
    	cout << typeid(c).name() << endl;
    	cout << typeid(d).name() << endl;
    
    	cout << a << endl;
    	cout << b<< endl;
    	cout << c << endl;
    	cout << d << endl;
    
    	//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    请添加图片描述

    🌷8.2 auto的使用规则

    • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
    #include 
    using namespace std;
    int main()
    {
    	int a = 10;
    	auto b = &a;   //自动推导出b的类型为int*
    	auto* c = &a;  //自动推导出c的类型为int*
    	auto& d = a;   //自动推导出d的类型为int
    	//打印变量b,c,d的类型
    	cout << typeid(b).name() << endl;//打印结果为int*
    	cout << typeid(c).name() << endl;//打印结果为int*
    	cout << typeid(d).name() << endl;//打印结果为int
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
    void TestAuto()
    {
     auto a = 1, b = 2; 
     auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    请添加图片描述

    🌷8.3 auto不能推导的场景

    • auto做为函数的参数
    // 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
    void TestAuto(auto a)
    {}
    
    • 1
    • 2
    • 3

    请添加图片描述

    • auto不能直接用来声明数组
    void TestAuto()
    {
    int a[] = {1,2,3};
    auto b[] = {456};
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    注意:

    • 为了避免与C++98中的auto发生混淆,C++11只保留了auto作为类型指示符的用法
    • auto在实际中最常见的优势用法就是跟以后会讲到的C++11提供的新式for循环,还有lambda表达式等
      进行配合使用。

    🌹9. 基于范围的for循环(C++11)

    🌷9.1 范围for的语法

    在C++98中如果要遍历一个数组,可以按照以下方式进行:

    void TestFor()
    {
    	 int array[] = { 1, 2, 3, 4, 5 };
    	 //将数组所有元素乘以2
    	 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; 
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

    void TestFor()
    {
         int array[] = { 1, 2, 3, 4, 5 };
         //将数组中所有元素乘以2
         for(auto& e : array)//记得是需要写出auto&
             e *= 2;
         
         for(auto e : array)
             cout << e << " ";
         
         return ;
     }
    
    int main()
    {
        TestFor();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

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


    🌷9.2 范围for的使用条件

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

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

    void TestFor(int array[])
    {
         for(auto& e : array)  //这里的array其实不是数组,数组在传参时会退化成指针
         cout<< e <<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述


    🌹10. 指针空值nullptr(C++11)

    🌷10.1 C++98中的指针空值

    在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针。如果一个指针没有合法的指向,我们基本都是按照如下方式对其进行初始化:

    int* p1 = NULL;
    int* p2 = 0;
    
    • 1
    • 2

    NULL其实是一个宏,在传统的C头文件(stddef.h)中可以看到如下代码:

    #ifndef NULL
    #ifdef __cplusplus
    #define NULL    0
    #else  
    #define NULL    ((void *)0)
    #endif  
    #endif  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

    #include 
    using namespace std;
    void Fun(int p)
    {
    	cout << "Fun(int)" << endl;
    }
    void Fun(int* p)
    {
    	cout << "Fun(int*)" << endl;
    }
    int main()
    {
    	Fun(0);           //打印结果为 Fun(int)
    	Fun(NULL);        //打印结果为 Fun(int)
    	Fun((int*)NULL);  //打印结果为 Fun(int*)
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 程序本意本意是想通过Fun(NULL)调用指针版本的Fun(int* p)函数,但是由于NULL被定义为0,Fun(NULL)最终调用的是Fun(int p)函数。
    • 在C++98中字面常量0,既可以是一个整型数字,也可以是无类型的指针(void*)常量,但编译器默认情况下将其看成是一个整型常量,如果要将其按照指针方式来使用,必须对其进行强制转换。

    注意:

    1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。
    2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。
    3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

    🍀测试代码

    #include 
    #include 
    #include 
    
    using namespace std;
    //namespace byh
    //{
    //    // 命名空间中可以定义变量/函数/类型
    //    int rand = 10;
    //    int Add(int left, int right)
    //        {
    //            return left + right;
    //        }
    //    struct Node
    //        {
    //            struct Node* next;
    //            int val;
    //        };
    //}
    2. 命名空间可以嵌套
    //namespace N1
    //    {
    //        int a = 20;
    //        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;
    //                    }
    //            }
    //    }
    3. 同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中。
    //namespace N1
    //    {
    //        int Mul(int left, int right)
    //            {
    //                return left * right;
    //            }
    //    }
    
    
    
    
    //int rand = 10;//变量和函数重名
    // C语言没办法解决类似这样的命名冲突问题,所以C++提出了namespace来解决
    //int main()
    //{
    //    printf("%d\n",byh :: rand);//rand是函数,编译会报错
    //    return 0;
    //}
    
    //using N1::a;
    //using namespace byh;
    //int main()
    //{
    //    int c = 1;
    //    int d = 2;
    //    printf("%d\n",byh::rand);
    //    printf("%d\n",a);
    //    printf("%d\n",Add(c, d));
    //    return 0;
    //}
    
    //std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
    //using namespace std;
    //
    //int main()
    //{
    //    int a = 1;
    //    float b = 2.1;
    //    double c= 2.111;
    //    char arr[10] = { 0 };
    //    char d[] = "hello world";
    //    cin >> arr;
    //    cout << arr << endl;//endl相当于换行 -> /n
    //    cout << a << endl;//C++的输入输出可以自动识别变量类型
    //    cout << b << endl;
    //    cout << c << endl;
    //    cout << d << endl;
    //    return 0;
    //}
    
    //using namespace std;
    //
    //int Add(int x, int y)
    //{
    //    return x + y;
    //}
    //
    //double Add(double x, double y)
    //{
    //    return x + y;
    //}
    //int main()
    //{
    //    cout << Add(0,1) << endl;//打印0+1的结果
    //    cout << Add(1.1,2.2) << endl;//打印1.1+2.2的结果
    //    return 0;
    //}
    //
    //short Add(short left, short right)
    //{
    //    return left+right;
    //}
    //int Add(short left, short right)
    //{
    //    return left+right;
    //}
    
    //#include
    //using namespace std;
    //
    //int main()
    //{
    //    int a = 1;
    //    int&b = a; //相当于给a起了一个别名为b,int是b的类型
    //    cout << a << endl;
    //    cout << b << endl;
    //    b = 100;  //改变b也就相当于改变了a
    //    cout << b << endl;
    //    cout << a << endl;
    //}
    
    //void TestRef()
    //{
    //    int a = 10;
    //    int& ra; // 该条语句编译时会出错
    //    int& ra = a;
    //    int& rra = a;
    //    printf("%p %p %p\n", &a, &ra, &rra);
    //}
    
    //void TestConstRef()
    //{
    //    //常引用是创建一个临时变量,引用名是临时变量的引用
    //    const int a = 10;
    //    //int& ra = a; // 该语句编译时会出错,a为常量,而且a为不可以修改
    //    const int& ra = a;
    //    // int& b = 10; // 该语句编译时会出错,b为常量
    //    const int& b = 10;
    //    double d = 12.34;
    //    //int& rd = d; // 该语句编译时会出错,类型不同
    //    const int& rd = d;
    //}
    
    
    //#include
    //using namespace std;
    //int main()
    //{
    //    int a = 10;
    //    //double&ra = a;
    //
    //
    //
    //    const double&ra = a;
    //}
    //
    //void Swap2(int& a, int& b) //通过引用来交换
    //{
    //    int tmp = a;
    //    a = b;
    //    b = tmp;
    //}
    //void Swap1(int* a, int *b) //通过指针来交换
    //{
    //    int tmp = *a;
    //    *a = *b;
    //    *b = tmp;
    //}
    
    //using namespace std;
    //int& Add(int a, int b)
    //{
    //    static int c = a + b;
    //    return c;
    //}
    //int main()
    //{
    //    int& ret = Add(1, 2);
    //    Add(3, 4);
    //    cout << "Add(1, 2) is :"<< ret <
    //    return 0;
    //}
    
    //int main()
    //{
    //     int a = 10;
    //     int& ra = a;
    //     cout<<"&a = "<<&a<
    //     cout<<"&ra = "<<&ra<
    //     return 0;
    //
    //}
    
    //int main()
    //{
    //     int a = 10;
    //
    //     int& ra = a;
    //     ra = 20;
    //
    //     int* pa = &a;
    //     *pa = 20;
    //
    //     return 0;
    //
    //}
    
    //#include
    //using namespace std;
    
    
    //int TestAuto()
    //{
    //    return 10;
    //}
    //int main()
    //{
    //    int a = 10;
    //    auto b = a;
    //    auto c = 'a';
    //    auto d = TestAuto();
    //
    //    cout << typeid(b).name() << endl; //这个地方要学到后面类的时候才可以解释,这里打印出的是类型名
    //    cout << typeid(c).name() << endl;
    //    cout << typeid(d).name() << endl;
    //
    //    cout << a << endl;
    //    cout << b<< endl;
    //    cout << c << endl;
    //    cout << d << endl;
    //
    //    //auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
    //    return 0;
    //}
    //
    void TestAuto()
    {
     auto a = 1, b = 2;
     auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
    }
    //
     此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
    void TestAuto(auto a)
    {}
    //
    //void TestAuto()
    //{
    //    int a[] = {1,2,3};
    //    auto b[] = {4,5,6};
    //}
    
    //void TestFor()
    //{
    //     int array[] = { 1, 2, 3, 4, 5 };
    //     //将数组所有元素乘以2
    //     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;
    //
    //}
    
    //void TestFor()
    //{
    //     int array[] = { 1, 2, 3, 4, 5 };
    //     //将数组中所有元素乘以2
    //     for(auto& e : array)//记得是需要写出auto&
    //         e *= 2;
    //
    //     for(auto e : array)
    //         cout << e << " ";
    //
    //     return ;
    // }
    //
    //int main()
    //{
    //    TestFor();
    //}
    
    //void TestFor(int array[])
    //{
    //     for(auto& e : array)  //这里的array其实不是数组,数组在传参时会退化成指针
    //     cout<< e <
    //}
    
    //#include 
    //using namespace std;
    //void Fun(int p)
    //{
    //    cout << "Fun(int)" << endl;
    //}
    //void Fun(int* p)
    //{
    //    cout << "Fun(int*)" << endl;
    //}
    //int main()
    //{
    //    Fun(0);           //打印结果为 Fun(int)
    //    Fun(NULL);        //打印结果为 Fun(int)
    //    Fun((int*)NULL);  //打印结果为 Fun(int*)
    //    return 0;
    //}
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
  • 相关阅读:
    openGauss学习笔记-124 openGauss 数据库管理-设置账本数据库-查看账本历史操作记录
    24 Bayes判别
    基于TCP的文件服务器
    SpringBoot + React Ant Design 实现图片上传到Minio 中
    简单秒表设计仿真verilog跑表,源码/视频
    vue3中使用ref调用子组件属性与方法
    terraform简单的开始-vpc cvm创建
    现代C++学习指南-类型系统
    元宇宙系列之AI虚拟人:“人”潮汹涌 探路未来
    uni-App获取地图address与高德地图API配合
  • 原文地址:https://blog.csdn.net/m0_60338933/article/details/126074603