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\n", p); //p 保存堆上开辟空间的地址
    printf("*p = %d\n", *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\n", 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\n", *pi); //1
    printf("*pf = %f\n", *pf); //2.000000
    printf("*pc = %c\n", *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\n", i); //0。可以直接写i,因为使用了First整个命名空间
    printf("Second::i = %d\n", Second::i);//1。须带命名空间的名字

    P  p = {2, 3};

    printf("p.x = %d\n", p.x);//2
    printf("p.y = %d\n", 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\n", p->x);
    printf("p->y = %d\n", 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\n", k); //5
    printf("j = %d\n", 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\n", x); //2
    printf("y = %d\n", y); //3
    printf("&x = %d\n", &x);
    printf("&y = %d\n", &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)

posted @ 2017-10-30 09:13  CrazyDiode  阅读(286)  评论(0编辑  收藏  举报