• 标准C++day1——名字空间和堆内存管理


    一、C++介绍

        本贾尼.斯特劳斯特卢普,于1979年在贝尔实验室负责分析UNIX系统内核流量的分布情况时,特别希望有一种更加模块化的工具,于1979.10开始着手研发一款新的编程语言,在C语言的基础上增加了面向对象的机制,也就是C++,1983年完成了C++的第一个版本

        C++与C的关联和重要区别:

        1、C++完全兼容C语言的所有内容

        2、支持面向对象的编程思想       //C是面对过程的

        3、支持运算符重载、函数重载的编译时多态机制 //抽象(封装) 继承 多态

        4、泛型编程、模版编程

        5、支持异常处理

        6、类型检查更加严格

        7、C++增加了名字空间的机制

    二、第一个C++程序

     

    1. #include
    2. using namespace std;
    3. int main(int argc,const char* argv[])
    4. {
    5. cout << "Hello World!" << endl;
    6. return 0;
    7. }

        1、文件扩展名由 .c 变成 .cpp  .cc  .C  .cxx

        2、编译器由gcc变成g++,gcc也可以继续使用,需要增加编译参数

            -xC++ -lstdc++

        3、C++语言的标准头文件不带.h,iostream意为in out stream,在C++中输入、输出被封装成了流操作(数据流),C语言的头文件还可以继续使用,但是标准C的头文件建议名字换成前面加c 后缀去掉的新名字 例如 cstdio,为了删除原C标准头文件中的大量的宏,重新放入名字空间中,防止命名冲突

        4、C++输入、输出

            cout    用于输出

            cin     用于输入

            不需要占位符,会自动识别数据类型

            printf/scanf 属于C标准库中的函数

            cout/cin 是C++标准库中的类对象  //不是函数

        5、增加了名字空间机制,是C++为了解决命名冲突而发明的一项机制

    三、C++与C数据类型的不同

        1、结构的不同

            a、不再需要通过typedef来缩短结构类型名,在C++中设计好结构后,定义结构类型时不再需要使用struct关键字了

            b、结构中可以有成员是成员函数、成员变量,结构变量、结构指针使用 . 和 -> 访问成员,如果是成员函数,那么可以直接访问同结构中的任何成员,不需要.和->

            c、结构中有一些隐藏的成员函数:构造函数、析构函数、拷贝构造、赋值操作

            d、结构可以继承其它结构,也可以被其他结构所继承

            e、可以给成员赋予访问控制属性

                public        公开的(默认)

                protected     保护的  结构内和继承了它的结构中能使用

                private       私有的  只有结构中才能使用

       

        2、联合的不同

            a、不再需要通过typedef来缩短联合类型名,在C++中设计好联合后,定义联合类型时不再需要使用union关键字了

            b、联合中可以有成员是成员函数、成员变量,联合变量、联合指针使用 . 和 -> 访问成员,如果是成员函数,那么可以直接访问同联合中的任何成员,不需要.和->

            c、联合中有一些隐藏的成员函数:构造函数、析构函数、拷贝构造、赋值操作

            d、可以给成员赋予访问控制属性

                public        公开的(默认)

                protected     保护的  联合内和继承了它的联合中能使用

                private       私有的  只有联合中才能使用

       

        3、枚举的不同

            a、不再需要通过typedef来缩短枚举类型名,在C++中设计好枚举后,定义枚举类型时不再需要使用enum关键字了

            b、C++编译器会对枚举的值进行检查,如果不符合就报错,只能给名字

            c、C语言使用整型来模拟的,C++中的枚举类型是一种真正的数据类型,所以不能与整型进行隐式类型转换了

       

        4、布尔类型的不同

            a、C++中有真正的布尔类型,bool、true、false 是C++的关键字,不再需要包含 stdbool.h 头文件

            b、true、false 在C++中是1字节,而C语言是4字节(int)   //bool不是C语言的关键字 所以写c需要导入头文件

            注意:无论C还是C++,bool类型变量只能存储0|1

       

        5、字符串的不同

            a、C++中的字符串被封装成了 string 类,可以与C语言的字符串进行转换

            b、string类被封装在 string 文件,并属于std名字空间,但是string已经被iostream包含

            c、使用string类,可以通过运算符的方式直接操作字符串,但是C语言string.h中的str系列函数也可以继续使用

                =   strcpy

                +=  strcat

                ==  strcmp  相同为真

                size() \ length()  strlen 只算字符个数

            d、C++中没有规定string类必须以'\0'结尾,编译器在实现时可以在结尾加上'\0'也可以不加,由编译器决定,因为string是一个类,它的长度信息已经被封装记录在私有成员变量中了

       

        6、void*的不同 

            在C语言中,void*类型可以与任意类型的指针进行自动转换

            在C++中,void*类型不可以自动转换成其他任意类型的指针,如果需要把void*类型的指针赋值给其他类型的指针时,必须通过强制类型转换后才能赋值,为了提高指针数据类型的安全性

            但是其他类型的指针还是可以自动转换成void*类型的指针,因为C语言标准库、系统函数中采用了大量的void*类型作为参数,如果不保留这个方式会导致C++在调用这些函数时非常麻烦

                int* p = (int*)malloc(4);

       

    四、名字空间

        1、为什么需要名字空间

            由于C++完全兼容C语言,C++标准库中自带大量的类、函数、宏,而且支持继承语法,导致全局的标识符大量增加,因此命名冲突的概率极大的增加,因此名字空间就是为了解决命名冲突

        2、什么是名字空间

            是C++中一种对命名空间进行逻辑划分的一种技术 

            namespace xxx

            {

                变量;

                函数;

                结构、联合、枚举;

                类;

                ...

            }  

            定义了名字空间后形成了一个相对封闭的作用域空间

        3、如何使用

            1、直接导入

                using namespace xxx;

                之后就可以直接使用名字空间中的所有内容,虽然方便,实际工作中不建议

            2、域限定符 ::

                xxx::标识符

        4、名字空间可合并

            名字空间可以被多次定义,不同位置的名字空间编译器会在编译时自动合并

            a.cpp

            namespace n1{int a;}

            b.cpp

            namespace n1{int b;}

            main.cpp

            using namespace n1;//  会把a、b都导入进来

        5、名字空间中的声明和定义可以分开

            a.h

            namespace n1{

                extern int num;

            }

            a.cpp

            int n1::num;

            注意:可以分开定义,但是必须加上 名字空间名::变量名

        6、匿名名字空间

            所有全局标识符都归属于同一个名字空间,称为匿名名字空间,可以通过 ::全局标识符 来指定访问匿名名字空间中的内容

            例如:同名的全局变量被同名局部变量屏蔽后,可以以此指定访问全局变量

        7、名字空间可以嵌套

           

    1. namespace n1{
    2.         int num = 10;
    3.         namespace n2{
    4.             int num = 20;
    5.             namespace n3{
    6.                 int num = 30;  
    7.             }
    8.         }  
    9.     }

            采用逐层分解访问

            n1::n2::n3::num

            导入指定层的名字空间

            using namespace n1::n2;

        8、可以给名字空间的名字取别名

            namespace n123 = n1::n2::n3

    五、C++的堆内存管理

        1、语法格式:

            类型* p = new 类型名;

                new 分配内存,相当于C语言的malloc  

            delete p;  

                delete 释放内存 相当于C语言的free(p)

        2、new 允许在分配内存时直接初始化内存

            类型* p = new 类型名(val);

            int* p = new int(10);

       

        3、new/delete 不能与 malloc/free 混合使用

            int* p = new int;

            free(p);

            虽然语法允许,但是不能这样混合使用

            因为使用new分配内存时,会自动调用结构、联合、类类型的构造函数,使用delete释放内存时,会自动调用结构、联合、类类型的析构函数

            但是malloc和free都不会调用,如果混用,就会导致构造、析构没有对应调用

        4、连续内存的申请和释放

            类型* p = new 类型名[个数];

                int* p = new int[10];//10个int类型的连续堆内存40字节

                new[] 会多次调用构造函数

            delete[] p;

                delete[]专门用于释放通过 new[] 申请出来的内存

                delete[]也会多次调用析构函数

            注意:malloc/free  new/delete  new[]/delete[] 都不能混用

            注意:通过new[]为结构、联合、类类型申请的内存的前4字节[-1]中记录了申请的次数,这样就可以让编译器知道需要调用多少次构造函数和析构函数

        5、重复释放问题

            delete可以释放空指针,但是也不能重复释放其他有效地址,与free一致

        6、内存分配失败 

            malloc分配内存失败会返回NULL

            new分配内存失败会抛出一个异常std::bad_array_new_length,如果不接异常并处理,那么会终止

        7、返回值类型不同

            malloc返回一个void*类型的指针

            new返回一个对应类型的指针

                        malloc/free   和   new/delete 的区别?

        身份(本质):          函数                                 关键字/运算符

        返回值:                void*                                对应类型的指针

        参数:                   字节个数(手动计算)          类型(自动计算字节个数)

        连续内存:            手动计算总字节数            new[个数]

        扩容:                    realloc                              无法直接处理

        失败:                    返回NULL                        抛异常

        构造\析构:           不调用                              调用

        初始化:               不能初始化                        可以初始化

        头文件:                stdlib.h                             不需要

        函数重载:            不允许重载                        允许

        内存分配的位置:  堆内存                              自由存储区

            注意:自由存储区是一个抽象的概念,而不是具体某个位置段,平时一般称new是分配在堆内存也问题不大,因为new底层默认调用了malloc,所以此时称分配在堆内存没问题,但是new可以像运算符一样被程序员重载或借助 new(地址) 类型 两种方式分配内存时,可以分配到其他内存段,所以称为自由存储区

  • 相关阅读:
    详细解读-Spring请求处理
    查准率(precision,也叫精确率)和查全率(recall,也叫召回率)
    原神游戏干货分享:探索璃月的宝箱秘密,提高游戏资源获取效率!
    专题18:Django之Form,ModelForm
    荔枝海盐的香味
    在国内企业做数据治理,建议您考个DAMA-CDGA/CDGP证书
    aiohttp从入门到精通
    编程向导-JavaScript-基础语法-算术/赋值/逗号/运算符
    Spark SQL 的总体工作流程
    Pytorch Advanced(二) Variational Auto-Encoder
  • 原文地址:https://blog.csdn.net/weixin_51479108/article/details/132745432