zoukankan      html  css  js  c++  java
  • C++深度解析教程学习笔记(4)C++中的新成员

    1. 动态内存分配

    (1)C++通过 new 关键字进行动态内存申请,是以类型为单位来申请空间大小的

    (2)delete 关键字用于内存释放

    ▲注意释放数组时要加[],否则只释放这个数组中的第 1 个元素。

    C++中的动态内存分配

    #include <stdio.h>
    int main()
    {
        int* p = new int;
        *p = 5;
        *p = *p + 10;
        printf("p = %p
    ", p); //p 保存堆上开辟空间的地址
        printf("*p = %d
    ", *p);//15
        delete p;
        p = new int[10];//申请 10 个 int 型空间
        for(int i=0;i<10; i++)
        {
            p[i] = i + 1;
            printf("p[%d] = %d
    ", i, p[i]);
        }
        delete[] p; //注意:释放数组时[]不能漏掉
        return 0;
    }

    2. new 关键字

    (1)对比 new 和 malloc

     

    new

    malloc

    性质

    是个关键字,属C++的一部分

    是由C库提供的函数

    申请单位

    以具体类型为单位

    以字节为单位

    内存初始化

    申请单个类型变量时可进行初始化

    不具备内存初始化的特性

    (2)new 关键字的初始化

    int* pi = new int(1);
    float* pf = new float(2.0f);
    char* pc = new char('c');

    初始化动态内存

    #include <stdio.h>
    
    int main()
    {
        int* pi = new int(1); //开辟1个int型空间,并初始化为1
        //int* pa = new int[1];//注意,这时申请一个数组,与前一行含义不同
    
        float* pf = new float(2.0f);
        char* pc = new char('c');
    
        printf("*pi = %d
    ", *pi); //1
        printf("*pf = %f
    ", *pf); //2.000000
        printf("*pc = %c
    ", *pc); //c
    
        delete pi;
        delete pf;
        delete pc;
    
        return 0;   
    }

    3. C++中的命名空间

    C++中命名空间概念用于解决名称冲突问题

    (1)在 C 语言中只有一个全局作用域

        ①C 语言中所有的全局标识符共享同一个作用域

        ②标识符之间可能发生冲突

    (2)C++中提出了命名空间的概念

         ①命名空间将全局作用域分成不同的部分

         ②不同命名空间中的标识符可以同名而不会发生冲突

         ③命名空间可以相互嵌套

         ④全局作用域也叫默认命名空间

    (3)C++命名空间的定义:namespace Name {}

         ①使用整个命名空间:using namespace name;

        ②使用命名空间中的变量:using name::variable;

        ③使用默认命名空间中的变量: ::variable

    命名空间的使用

    #include <stdio.h>
    
    namespace First
    {
        int i = 0;
    }
    
    namespace Second
    {
        int  i = 1;
    
        //命名空间的嵌套
        namespace Internal
        {
            struct P
            {
                int x;
                int y;
            };
        }
    }
    
    int main()
    {
        using namespace First;//使用First整个命名空间
        using Second::Internal::P;//使用命名空内部的P结构体
    
        printf("Fisrt::i = %d
    ", i); //0。可以直接写i,因为使用了First整个命名空间
        printf("Second::i = %d
    ", Second::i);//1。须带命名空间的名字
    
        P  p = {2, 3};
    
        printf("p.x = %d
    ", p.x);//2
        printf("p.y = %d
    ", p.y);//3
    
        return 0;   
    }

    4.新型的类型转换

    4.1. C 方式的强制类型转换

    (1)转换形式

        ①(Type)(Expression)

        ②Type(Expression) //老式的

    #include <stdio.h>
    
    typedef void PF(int);
    
    struct Point
    {
        int x;
        int y;
    };
    
    int main()
    {
        int v = 0x12345;
        PF* pf = (PF*)v;
        char c = char(v);//老式写法,很像函数调用
        Point* p = (Point*)v;
    
        pf(5);
    
        printf("p->x = %d
    ", p->x);
        printf("p->y = %d
    ", p->y);
    
        return 0;
    }

    (2)强制类型转换存在的问题

    ①过于粗暴:任意类型之间都可以进行转换,编译器很难判断其正确性

    ②难于定位:在源码中无法快速定位所有使用强制类型转换的语句

    4.2. C++中新式的 4 种强制类型转换

    (1)用法:xxx_cast(Type)(Expression)

    (2)4 种类型

    类型

    适用范围

    举例

    备注

    static_cast

    ①基本类型之间

    ②不能用于基本类型的指针之间

    ③类与子类对象之间的转换或类指针间转换

    int i = 0;

    char c = 'A';

    int* pi = &i;

    char* pc = &c;

    c = static_cast<char>(i); //ok

    //不能用于基本类型的指针间转换

    pc = static_cast<char*>(pi);//oops

     

    const_cast

    目标类型(即尖括号内的类型)必须是指针或引用

    //i有内存,因别名,每次从内存读取i

    const int& i = 1;//i为引用

    int& a = const_cast<int&>(i);

    const int j = 1;

    //为j分配内存,但不会去用它,从符号表中取j

    int&  b = const_cast<int&>(j);

    a = 5; //i==5;a==5;

    b = 3; //j==1,b==3;

    用于去除变量的const属性

    reinterpret_cast

    ①用于指针类型间

    ②用于整数和指针类型之间

    typedef void PF(int);

    int i = 0;

    char c = 'c';

    int* pi = reinterpret_cast<int*>(&c);

    char*pc = reinterpret_cast<char*>(&i);

    PF*pf= reinterpret_cast<PF*>(0x12345678);

    //以下错,要用static_cast

    c = reinterpret_cast<char>(i);

    reinterpret_cast直接从二进制位进行复制,是一种极其不安全的转换。

    dynamic_cast

    ①用于有继承关系的类指针间。②用于有交叉关系的类指针之间

    详见后面章节的分析

    ①dynamic_cast具有类型检查的功能

    ②需要虚函数的支持

    #include <stdio.h>
    
    void static_cast_demo()
    {
        int i = 0x12345;
        char c = 'c';
        int* pi = &i;
        char* pc = &c;
    
        c = static_cast<char>(i);//基本类型
    
        //基本类型的指针间,非法
        //pc = static_cast<char*>(pi);  
    }
    
    void const_cast_demo()
    {
    
        //用常量初始化引用,要分配内存。故j为变量,因加const而成只读变量
        const int& j = 1;//j为引用--》只读变量,说明j不能做为左值而己
        int& k = const_cast<int&>(j); //转为普通引用,k就是j的别名
    
        k = 5;
    
        printf("k = %d
    ", k); //5
        printf("j = %d
    ", j); //5
    
        const int x = 2; //x为常量
        int& y = const_cast<int&>(x);//此时,会为x分配内存
        //int z = const_cast<int>(x);  //oops,目标类型只能是引用或指针
    
        y = 3;
    
        printf("x = %d
    ", x); //2
        printf("y = %d
    ", y); //3
        printf("&x = %d
    ", &x);
        printf("&y = %d
    ", &y); //x与y的内存地址是相同的
    }
    
    void reinterpret_cast_demo()
    {
        int i = 0;
        char c = 'c';
        int* pi = &i;
        char* pc = &c;
    
        pc = reinterpret_cast<char*>(pi); //ok,指针间
        pi = reinterpret_cast<int*>(pc);  //ok,指针间
        pi = reinterpret_cast<int*>(i);   //ok,整数与指针间
        //c  = reinterpret_cast<char>(i);   //oops,基本类型间转换,要用static_cast
    
    }
    
    void dynamic_cast_demo()
    {
        int i = 0;
        int* pi = &i;
        char* pc = dynamic_cast<char*>(pi);//oops,目标类型应为类的指针或引用
    }
    
    int main()
    {
        static_cast_demo();
        const_cast_demo();
    
        reinterpret_cast_demo();
        dynamic_cast_demo();
        return 0;
    }

    新式类型转换以 C++关键字的方式出现

    ①编译器能够帮助检查潜在的问题

    ②非常方便的在代码中定位

    ③支持动态类型识别(dynamic_cast)

  • 相关阅读:
    PHP按权重随机
    PHP将汉字转为拼音
    php支持解密的加密算法示例
    小波变换检测信号突变点的MATLAB实现
    OFDM通信系统的MATLAB仿真(2)
    OFDM通信系统的MATLAB仿真(1)
    java.lang.reflect.Constructor.getParameterTypes()方法示例
    createQuery 与 createNativeQuery 区别
    java.lang.StringBuilder.deleteCharAt()方法实例
    String.format()详细用法
  • 原文地址:https://www.cnblogs.com/CoderTian/p/7753053.html
Copyright © 2011-2022 走看看