C++入门基础(上篇)——命名空间、输入输出、缺省参数、函数重载、引用

目录

一.C++入门基础

1.C++的包括

2.C++发展历史

2.1 C++版本更新

2.2 C++的诟病

3. C++参考文档

4. C++的重要性

4.1 编程语言排行榜

4.2 C++在工作领域中的应用

5. C++学习建议和书籍推荐

5.1 C++学习难度

5.2 学习书籍推荐(主要以中后期书籍为主)

6.C++的第一个程序

7. 命名空间

7.1 namespace的价值

7.2 namespace的定义

7.3 命名空间使用

8. C++输入&输出(C++可兼容C语言)

9. 缺省参数

(在数据结构的实践应用时使用缺省参数,可以避免扩容)

10. 函数重载

11. 引用

11.1引用的概念和定义


一.C++入门基础

1.C++的包括

        C++具体学习内容包括C++语法、STL、高阶数据结构这几个部分。

2.C++发展历史

        C++的起源可以追溯到1979年,当时Bjarne Stroustrup(本贾尼·斯特劳斯特卢普,这个翻译的名字不同的地⽅可能有差异)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的软件开发任务,特别是模拟和操作系统的开发⼯作,他感受到了现有语⾔(如C语⾔)在表达能力、可维护性和可扩展性⽅⾯的不⾜。
        1983年,Bjarne Stroustrup在C语⾔的基础上添加了⾯向对象编程的特性,设计出了C++语⾔的雏形,此时的C++已经有了类、封装、继承等核⼼概念,为后来的⾯向对象编程奠定了基础。这⼀年该语⾔被正式命名为C++。
        在随后的⼏年中,C++在学术界和⼯业界的应⽤逐渐增多。⼀些⼤学和研究所开始将C++作为教学和研究的⾸选语⾔,⽽⼀些公司也开始在产品开发中尝试使⽤C++。这⼀时期,C++的标准库和模板等特性也得到了进⼀步的完善和发展。
        C++的标准化⼯作于1989年开始,并成⽴了⼀个ANSI和ISO(International Standards Organization)国际标准化组织的联合标准化委员会。1994年标准化委员会提出了第⼀个标准化草
案。在该草案中,委员会在保持斯特劳斯特卢普最初定义的所有特征的同时,还增加了部分新特征。
        在完成C++标准化的第⼀个草案后不久,STL(Standard Template Library)是惠普实验室开发的⼀系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室⼯作时所开发出来的。在通过了标准化第⼀个草案之后,联合标准化委员会投票并通过了将STL包含到C++标准中的提议。STL对C++的扩展超出C++的最初定义范围。虽然在标准中增加STL是个很重要的决定,但也因此延缓了C++标准化的进程。
        1997年11⽉14⽇,联合标准化委员会通过了该标准的最终草案。1998年,C++的ANSI/IS0标准被投⼊使⽤。

2.1 C++版本更新

年份

C++ 标准名称非正式名称
1998ISO/IEC 14882:1998C++98
2003ISO/IEC 14882:2003C++03
2011ISO/IEC 14882:2011C++11
2014ISO/IEC 14882:2014C++14
2017ISO/IEC 14882:2017C++17
2020ISO/IEC 14882:2020C++20

2.2 C++的诟病

        C++⼀直被诟病的⼀个地⽅就是⼀直没出网络库(networking ) networking之前是在C++23的计划中 的,现在C++23已经发布了,但是没有networking。

3. C++参考文档

        多以英文版为主,我们作为程序员要学会读英文和看英文,这样更能面向世界、面向国际、跟随世界时代发展潮流。

https://legacy.cplusplus.com/reference/
https://zh.cppreference.com/w/cpp
https://en.cppreference.com/w/
说明:第⼀个链接不是C++官⽅文档,标准也只更新到C++11,但是以头文件形式呈现,内容比较易看好懂。后两个链接分别是C++官⽅⽂档的中文版和英文版,信息很全,更新到了最新的C++标准,但是相比第⼀个不那么易看;几个文档各有优势,我们结合着使用。

4. C++的重要性

4.1 编程语言排行榜

        TIOBE排行榜是根据互联⽹上有经验的程序员、课程和第三方厂商的数量,并使用搜索引擎(如 Google、Bing、Yahoo!)以及Wikipedia、Amazon、YouTube和Baidu(百度)统计出排名数据,只是反映某个编程语⾔的热⻔程度,并不能说明一门编程语⾔好不好,或者一门语言所编写的代码数量多少。
2024年6月TIOBE发布的编程语言排行榜:

4.2 C++在工作领域中的应用

C++的应⽤领域服务器端、游戏(引擎)、机器学习引擎、⾳视频处理、嵌⼊式软件、电信设备、金融应用、基础库、操作系统、编译器、基础架构、基础⼯具、硬件交互等很多方面都有。
1. 大型系统软件开发:
        如编译器、数据库、操作系统、浏览器等等。
2. 音视频处理:
        常⻅的⾳视频开源库和⽅案有FFmpeg、WebRTC、Mediasoup、ijkplayer,⾳视频开发最主要的技术栈就是C++。
3. PC客户端开发:
        ⼀般是开发Windows上的桌⾯软件,⽐如WPS之类的,技术栈的话⼀般是C++和QT,QT 是⼀个跨平台的 C++图形⽤户界面(Graphical User Interface,GUI)程序。
4. 服务端开发:
        各种⼤型应⽤⽹络连接的⾼并发后台服务。这块Java也比较多,C++主要用于⼀些对性能要求⽐较⾼的地⽅。如:游戏服务、流媒体服务、量化⾼频交易服务等。
5. 游戏引擎开发:
        很多游戏引擎就都是使⽤C++开发的,游戏开发要掌握C++基础和数据结构,学习图形学知识,掌握游戏引擎和框架,了解引擎实现,引擎源代码可以学习UE4、Cocos2d-x等开源引擎实现。
6. 嵌入式开发:
        嵌⼊式把具有计算能⼒的主控板嵌⼊到机器装置或者电⼦装置的内部,通过软件能够控制这些装置。比如:智能⼿环、摄像头、扫地机器⼈、智能⾳响、⻔禁系统、⻋载系统等等,粗略⼀点,嵌⼊式开发主要分为嵌⼊式应⽤和嵌⼊式驱动开发。
7. 机器学习引擎:
        机器学习底层的很多算法都是⽤C++实现的,上层⽤python封装起来。如果你只想准备数据训练模型,那么学会Python基本上就够了,如果你想做机器学习系统的开发,那么需要学会C++。
8. 测试开发/测试:
        每个公司研发团队,有研发就有测试,测试主要分为测试开发和功能测试,测试开发⼀般是使⽤⼀些测试⼯具(selenium、Jmeter等),设计测试⽤例,然后写⼀些脚本进⾏⾃动化测试,性能测试等,有些还需要⾃行开发⼀些测试⽤具。功能测试主要是根据产品的功能,设计测试⽤例,然后⼿动的⽅式进⾏测试。

5. C++学习建议和书籍推荐

5.1 C++学习难度

        C++是⼀个相对难学难精的语⾔,相⽐其他⼀些语⾔,学习难度要⾼⼀些要陡峭⼀些,但总体来说学习难度趋于平缓,C++不像Java一样,Java是前期学习难度较为简单易懂,但后期却成指数级难度增加,这对于我们后期Java的学习,是有点吃力的。C++这门语言,这里有历史包袱的问题,也有语⾔本⾝设计和发展历史的问题。

5.2 学习书籍推荐(主要以中后期书籍为主)

C++ Primer:主要讲解语法,经典的语法书籍,前后中期都可以看,前期如果⾃学看可能会有点晦涩难懂,能看懂多少看懂多少,就当预习,中后期作为语法字典,⾮常好⽤。
STL源码剖析:主要从底层实现的⻆度结合STL源码,庖丁解⽜式剖析STL的实现,是侯捷⽼师的经典之作。可以很好的帮助我们学习别⼈⽤语法是如何实现出⾼效简洁的数据结构和算法代码,如何使⽤泛型封装等。中后期可以看。
Effctive C++:本书也是侯捷⽼师翻译的,本书有的⼀句评价,把C++程序员分为看过此书的和没看过此书的。本书主要讲了55个如何正确⾼效使⽤C++的条款,建议中后期可以看⼀遍,⼯作1-2年后再看⼀遍,相信会有不⼀样的收获。

6.C++的第一个程序

        C++兼容C语言绝大多数的语法,所以C语⾔实现的hello world依旧可以运⾏,C++中需要把定义文件代码后缀改为.cpp,VS编译器看到是.cpp就会调⽤C++编译器编译,linux下要用g++编译,不再是gcc
// test.cpp
#include<stdio.h>

int main()
{
    printf("hello world\n");
    return 0;
}
当然C++有⼀套自己的输入输出,严格说C++版本的hello world应该是这样写的:
// test.cpp
// 这⾥的std cout等我们都看不懂,没关系,下⾯我们会依次讲解
#include<iostream>
using namespace std;

int main()
{
    cout << "hello world\n" << endl;
    return 0;
}

7. 命名空间

7.1 namespace的价值

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

        在C语⾔项⽬中,类似下⾯程序这样的命名冲突是普遍存在的问题,这在多人开发程序项目时,因为每个人的命名习惯和命名方式不同,所以会经常遇到此类问题。C++引⼊namespace就是为了更好地处理这样的问题。

        下面的程序中,rand在头文件中是一个函数,在预处理阶段中,编译器会先把头文件先展开,而代码中程序员却把rand定作为一个变量,这就跟rand函数产生了命名冲突。

#include <stdio.h>
#include <stdlib.h>

int rand = 10;

int main()
{
    // 编译报错:error C2365: “rand”: 重定义;以前的定义是“函数”
    printf("%d\n", rand);
    return 0;
}

7.2 namespace的定义

  1. 定义命名空间,需要使⽤到namespace关键字后⾯跟命名空间的名字,然后接⼀对{},{}中即为命名空间的成员命名空间的结构跟结构体结构差不多,但是不同的是{}后面不加分号。命名空间中可以定义变量/函数/类型等。
  2. namespace本质是定义出一个域,该域跟全局域各自独立,不同的域可以定义同名变量。
    #include <stdlib.h>
    #include <string.h>
    
    int x = 0;
    
    namespace bit
    {
        int x = 1;
    }
    
    void func()
    {
        int x = 2;
    }
    
    int main()
    {
        int x = 3;
        
        //第一种:处理方式是先局部搜索,再全局搜索
        printf("%d\n", x);
    
        //第二种:直接访问命名空间里面的变量
        printf("%d\n", bit::x);
    
        //第三种:左边什么都没有的话,就是默认访问全局变量
        printf("%d\n", ::x);
    }
    

    以上代码更能体现域,全局变量和局部变量的作用和性质,具有典型代表的作用。重点:以下其中的三种不同的表达方式分别表示不同的变量,是对这几个概念重点的理解:

  3. C++中域有函数局部域,全局域,命名空间域,类域;域影响的是编译时语法查找⼀个变量/函数/类型出处(声明或定义)的逻辑,所以有了域隔离,名字冲突就解决了。局部域和全局域除了会影响编译查找逻辑,还会影响变量的⽣命周期命名空间域和类域不影响变量⽣命周期。例如:下面代码中命名空间bite中的rand变量是全局变量,编译时的语法查找时不会去在命名空间里查找。
  4. 重点:第一,::是域作用限定符。第二,若不使用命名空间的话,会默认访问的是全局变量的指针(地址),不会到命名空间去查找;反之,则使用指定的命名空间中的指针(地址)。
    #include <stdio.h>
    #include <stdlib.h>
    
    // 1. 正常的命名空间定义
    // bite是命名空间的名字,⼀般开发中是⽤项⽬名字做命名空间名。
    
    namespace bite
    {
        // 命名空间中可以定义变量/函数/类型
        int rand = 10;
    
        int Add(int left, int right)
        {
            return left + right;
        }
    
        struct Node
        {
            struct Node* next;
            int val;
        };
    }
    
    void func()
    {
        printf("%d\n", bit::rand++);
        //此时可以体现出来rand此时是全局变量
    }
    
    int main()
    {
        func();
    
        // 这⾥默认是访问的是全局的rand函数指针
        printf("%p\n", rand);
    
        // 这⾥指定bit命名空间中的rand
        printf("%d\n", bite::rand);
    
        bit::Add(1, 2);
        
        struct bit::Node node;
        
        const char* str = "hello world";
        
        strlen(str);
    
        return 0;
    }
  5. namespace只能定义在全局(因为本质是为了隔离),可以嵌套定义
    #include <stdio.h>
    
    namespace bite
    {
        // 小明
        namespace xiaoming
        {
            int rand = 1;
            int Add(int left, int right)
            {
                return left + right;
            }
        }
    
        // 小红
        namespace xiaohong
        {
            int rand = 2;
            int Add(int left, int right)
            {
                return (left + right)*10;
            }
        }
    
    }
    
    int main()
    {
    
        printf("%d\n", bite::xiaoming::rand);
        printf("%d\n", bite::xiaohong::rand);
        printf("%d\n", bite::xiaoming::Add(1, 2));
        printf("%d\n", bite::xiaohong::Add(1, 2));
        return 0;
    
    }
  6. 项⽬⼯程中多⽂件中定义的同名namespace会认为是⼀个namespace,不会冲突——即当多⽂件中可以定义同名namespace,他们会默认合并到⼀起,就像同⼀个namespace⼀样。以下使用数据结构中栈和队列的例子来说明这个原理:
    // Stack.h
    
    #pragma once
    #include<stdio.h>
    #include<stdlib.h>
    #include<stdbool.h>
    #include<assert.h>
    
    namespace bit
    {
        typedef int STDataType;
        typedef struct Stack
        {
            STDataType* a;
            int top;
            int capacity;
        }ST;
    
        void STInit(ST* ps, int n);
        void STDestroy(ST* ps);
        void STPush(ST* ps, STDataType x);
        void STPop(ST* ps);
        STDataType STTop(ST* ps);
        int STSize(ST* ps);
        bool STEmpty(ST* ps);
    }
    
    
    // Stack.cpp
    
    #include"Stack.h"
    
    namespace bit
    {
        void STInit(ST* ps, int n)
        {
            assert(ps);
            ps->a = (STDataType*)malloc(n * sizeof(STDataType));
            ps->top = 0;
            ps->capacity = n;
        }
    
        // 栈顶
        void STPush(ST* ps, STDataType x)
        {
            assert(ps);
            // 满了, 扩容
            if (ps->top == ps->capacity)
            {
                printf("扩容\n");
                int newcapacity = ps->capacity == 0 ? 4 : ps->capacity* 2;
                STDataType* tmp = (STDataType*)realloc(ps->a,
                newcapacity * sizeof(STDataType));
                if (tmp == NULL)
                {
                    perror("realloc fail");
                    return;
                }
                ps->a = tmp;
                ps->capacity = newcapacity;
            }
            ps->a[ps->top] = x;
            ps->top++;
        }
    }
    
    // Queue.h
    
    #pragma once
    #include<stdlib.h>
    #include<stdbool.h>
    #include<assert.h>
    
    namespace bit
    {
        typedef int QDataType;
        typedef struct QueueNode
        {
            int val;
            struct QueueNode* next;
        }QNode;
        typedef struct Queue
        {
            QNode* phead;
            QNode* ptail;
            int size;
        }Queue;
        void QueueInit(Queue* pq);
        void QueueDestroy(Queue* pq);
    
        // ⼊队列
        void QueuePush(Queue* pq, QDataType x);
    
        // 出队列
        void QueuePop(Queue* pq);
        QDataType QueueFront(Queue* pq);
        QDataType QueueBack(Queue* pq);
        bool QueueEmpty(Queue* pq);
        int QueueSize(Queue* pq);
    }
    
    // Queue.cpp
    
    #include"Queue.h"
    
    namespace bit
    {
        void QueueInit(Queue* pq)
        {
            assert(pq);
            pq->phead = NULL;
            pq->ptail = NULL;
            pq->size = 0;
        }
    }
    
    // test.cpp
    
    #include"Queue.h"
    #include"Stack.h"
    
    // 全局定义了⼀份单独的Stack
    typedef struct Stack
    {
        int a[10];
        int top;
    }ST;
    
    void STInit(ST* ps){}
    void STPush(ST* ps, int x){}
    
    int main()
    {
        // 调⽤全局的
        ST st1;
        STInit(&st1);
        STPush(&st1, 1);
        STPush(&st1, 2);
        printf("%d\n", sizeof(st1));
        // 调⽤bit namespace的
        bit::ST st2;
        printf("%d\n", sizeof(st2));
        bit::STInit(&st2);
        bit::STPush(&st2, 1);
        bit::STPush(&st2, 2);
        return 0;
    }
  7. C++标准库都放在⼀个叫std(standard)的命名空间中,这样就会将标准库封装起来,不会和程序员写的东西相冲突。

7.3 命名空间使用

        编译查找⼀个变量的声明/定义时,默认只会在局部或者全局查找,不会到命名空间里面去查找。所以下⾯程序会编译报错。所以我们要使⽤命名空间中定义的变量/函数,有三种方式:
  1. 指定命名空间访问,项⽬中推荐这种⽅式。
  2. using将命名空间中某个成员展开,项⽬中经常访问的不存在冲突的成员推荐这种⽅式。
    #include<stdio.h>
    namespace bite
    {
        int a = 0;
        int b = 1;
    }
    
    // using将命名空间中某个成员展开
    using bite::b;
    
    int main()
    {
        printf("%d\n", bite::a);
        printf("%d\n", b);
        return 0;
    }
  3. 展开命名空间中全部成员(即暴露到全局中去),这跟展开头文件不是一个意思,所以项⽬不推荐,冲突⻛险很⼤,⽇常⼩练习程序为了⽅便推荐使⽤。
    #include<stdio.h>
    
    namespace bite
    {
        int a = 0;
        int b = 1;
    }
    
    // 展开命名空间中全部成员
    using namespce bite;
    
    int main()
    {
        printf("%d\n", a);
        printf("%d\n", b);
        return 0;
    }

8. C++输入&输出(C++可兼容C语言)

  1. <iostream> 是 Input Output Stream 的缩写,是标准的输⼊、输出流库,定义了标准的输⼊、输出对象。
  2. std::cin 是 istream 类的对象,它主要⾯向窄字符(narrow characters (of type char))的标准输⼊流。在内存中有整型、字符型、浮点型等等各种类型,它们通过CPU处理进行各种运算;但在其他形式的设备中,比如文件等,想要输出到控制台或终端上的话,都需要转化为字符再输出。若需要控制精度输出的话,一般都是用printf函数来控制精度,比较简单方便。
  3. std::cout 是 ostream 类的对象,它主要⾯向窄字符的标准输出流。
  4. std::endl 是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。它的作用就是插入换行符并刷新流,本质上比较复杂。

    #include <iostream>
    
    int main()
    {
        //流插入
        std::cout << "hello world\n";
        
        //可连续进行流插入,不同类型的可自动识别变量的类型
        int i = 10;
        std::cout << i << '\n'<< "\n";
    
        double d = 1.1;
        std::cout << d << std::endl;
    
        //其实本质上跟printf差不多
        std::cin >> i >> d;
        std::cout << i << ":" << d << std::endl;
    
        scanf("%d%lf", &i, &d);
        printf("%d %lf\n", i, d);
    
        return 0;
    }
  5. <<是流插⼊运算符,>>是流提取运算符。(这两个运算符可以生动形象化为一个箭头,箭头指向的是内容流向的位置,它们可以自动识别变量的类型)(C语⾔还⽤这两个运算符做位运算左移/右移。)
  6. 使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式,C++的输⼊输出可以⾃动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是C++的流能更好的⽀持⾃定义类型对象的输⼊输出。
  7. IO流涉及类和对象,运算符重载、继承等很多⾯向对象的知识,这里先简单认识⼀下C++ IO流的⽤法。
  8. cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要通过命名空间的使⽤⽅式去⽤他们
  9. ⼀般⽇常练习中我们可以using namespace std,实际项⽬开发中不建议using namespace std。
  10. <iostream>间接包含了<stdio.h>,所以也可以使⽤printf和scanf,VS系列编译器可以这样,但在其他编译器可能会报错,比如Linux编译器。
  11. 通过cout和cin这些输入或输出的结果,并不是直接就输出或输入到控制台上去的,而是先到内部的一个缓冲区,类似数组,在缓冲区中要等遇到一些刷新标志,比如换行符,才能转化为字符后,才能传到控制台或终端中去。若缓冲区中有内容还未刷新出去的话,会先刷新出去,再进行输入输出数据,因此这样C++IO效率会慢很多。在IO需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码可以提⾼C++IO效率:
    #include<iostream>
    
    using namespace std;
    
    int main()
    {
        // 在io需求⽐较⾼的地⽅,如部分⼤量输⼊的竞赛题中,加上以下3⾏代码
        // 可以提⾼C++IO效率
        ios_base::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
    
        return 0;
    }

9. 缺省参数

(在数据结构的实践应用时使用缺省参数,可以避免扩容)

  1. 缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数。(有些地⽅把缺省参数也叫默认参数)
    #include <iostream>
    #include <assert.h>
    
    using namespace std;
    
    void Func(int a = 0)
    {
        cout << a << endl;
    }
    
    int main()
    {
        Func(); // 没有传参时,使⽤参数的默认值
        Func(10); // 传参时,使⽤指定的实参
    
        return 0;
    }
  2. 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。
  3. 带缺省参数的函数调⽤,C++规定必须从左到右依次给实参,不能跳跃给实参。
    #include <iostream>
    
    using namespace std;
    
    // 全缺省
    void Func1(int a = 10, int b = 20, int c = 30)
    {
        cout << "a = " << a << endl;
        cout << "b = " << b << endl;
        cout << "c = " << c << endl << endl;
    }
    
    // 半缺省
    void Func2(int a, int b = 10, int c = 20)
    {
        cout << "a = " << a << endl;
        cout << "b = " << b << endl;
        cout << "c = " << c << endl << endl;
    }
    
    //不可以这样跳跃传参,必须从左到右依次连续缺省,所以以下这段代码是不对的:
    void Func2(int a = 10, int b, int c = 20)
    //或void Func2(int a = 10, int b = 10, int c)
    {
        cout << "a = " << a << endl;
        cout << "b = " << b << endl;
        cout << "c = " << c << endl << endl;
    }
    
    int main()
    {
        Func1();
        Func1(1);
        Func1(1,2);
        Func1(1,2,3);
    
        //下面这句C++是不支持这样传参的,不能这么传参
        Func(,2,);
        //或Func(,2,3);
    
        Func2(100);
        Func2(100, 200);
        Func2(100, 200, 300);
    
        return 0;
    }
  4. 函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
    // Stack.h
    
    #include <iostream>
    #include <assert.h>
    
    using namespace std;
    
    typedef int STDataType;
    
    typedef struct Stack
    {
        STDataType* a;
        int top;
        int capacity;
    }ST;
    
    void STInit(ST* ps, int n = 4);
    
    
    // Stack.cpp
    
    #include"Stack.h"
    
    // 缺省参数不能声明和定义同时给
    void STInit(ST* ps, int n)
    {
        assert(ps && n > 0);
        ps->a = (STDataType*)malloc(n * sizeof(STDataType));
        ps->top = 0;
        ps->capacity = n;
    }
    
    
    // test.cpp
    
    #include"Stack.h"
    
    int main()
    {
        ST s1;
        STInit(&s1);
    
        // 确定知道要插⼊1000个数据,初始化时⼀把开好,避免扩容
        ST s2;
        STInit(&s2, 1000);
    
        return 0;
    }

10. 函数重载

        C++⽀持在同⼀作⽤域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调⽤就表现出了多态⾏为,使⽤更灵活。而C语⾔是不⽀持同⼀作⽤域中出现同名函数的。(平时会使用特别多)

        返回值不同不能作为重载条件,因为调⽤时也⽆法区分;但是参数不同是可以区分的,有类型不同的区分。

#include<iostream>

using namespace std;

// 1、参数类型不同
int Add(int left, int right)
{
    cout << "int Add(int left, int right)" << endl;
    return left + right;
}

double Add(double left, double right)
{
    cout << "double Add(double left, double right)" << endl;
    return left + right;
}

// 2、参数个数不同
void f()
{
    cout << "f()" << endl;
}

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

// 3、参数类型顺序不同(本质还是类型不同)
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;
}

// 返回值不同不能作为重载条件,因为调⽤时也⽆法区分
//void fxx()
//{}
//
//int fxx()
//{
//    return 0;
//}

// 下⾯两个函数构成重载
// f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁
void f1()
{
    cout << "f()" << endl;
}

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

int main()
{
    Add(10, 20);
    Add(10.1, 20.2);

    f();
    f(10);
    f(10, 'a');
    f('a', 10);

    return 0;
}

11. 引用

11.1引用的概念和定义

        引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名 编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间
        类型& 引用别名 = 引用对象;

        C++中为了避免引⼊太多的运算符,会复⽤C语⾔的⼀些符号,⽐如前⾯的<< 和 >>,这⾥引⽤也和取地址使⽤了同⼀个符号&,⼤家注意使⽤⽅法⻆度区分就可以。

     a、b、c、d的本质是指向同一个地方的地址,即为0     最经典的就是,使用引用直接进行替换。

注意:引用是给变量取别名,typedef是给类型取别名,#define是定义一个宏的常量,是替换作用。这三者本质上不一样,天差地别,要注意区分,不要混用。

#include<iostream>

using namespace std;

int main()
{
    int a = 0;

    // 引⽤:b和c是a的别名
    int& b = a;
    int& c = a;

    // 也可以给别名b取别名,d相当于还是a的别名
    int& d = b;

    ++d;

    // 这⾥取地址我们看到是⼀样的
    cout << &a << endl;
    cout << &b << endl;
    cout << &c << endl;
    cout << &d << endl;

    //运用到指针上同样可以
    int* p1 = &a;
    int*& p2 = p1;
    int e = 10;
    p2 = &e;

    cout << *p1 << end1;//输出的结果是10

    return 0;
}

  • 18
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值