新的关键字

动态内存分配

C++中的动态内存分配

--C++中通过new关键字进行动态内存申请

--C++中的动态内存申请是基于类型进行的

--delete关键字用于内存释放

变量申请:

Type* pointer = new Type;

// ......

delete pointer;

数组申请:

Type* pointer = new Type[N];

// ......

delete[] pointer;

例:

#include <stdio.h>
int main(int argc, char *argv[])
{
    int* p = new int; //p指向堆空间一个int类型变量     
    *p = 5;   
    *p = *p + 10;    
    printf("p = %p\n",p);
    printf("*p = %d\n",*p);   
    delete p;  //释放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; //释放p所指向的数组,如果此处为delete p,C++编译器会认为p指向的是一个单个元素,从而导致9个int空间内存泄露,所以一定要加上数组标示符[] 
    ......
}

new关键字与malloc函数的区别

--new关键字是C++的一部分,malloc是由C库提供的函数

   --malloc不属于C语言,而new关键字属于C++,C++兼容为C语言,C++里面还可以调用malloc函数

--new具体类型为单位进行内存分配,malloc只能以字节为单位进行内存分配

--new在申请单个类型变量时可进行初始化,malloc不具备内存初始化的特性

例: 

          int* pi = new int(1); //用1对pi指向的new int出来的内存空间进行初始化 
          float* pf = new float(2.0f); //用2.0f对pf指向的申请的float变量进行初始化 
          char* pc = new char('c'); //用'c'对pc指向的申请的char类型变量进行初始化 
    
          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;


C++中的命名空间

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

--C语言中所有的全局标示符共享同一个作用域,标示符之间可能发生冲突

--C++中提出了命名空间的概念

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

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

——命名空间可以相互嵌套

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


C++命名空间的定义:

namespace  name {/* ... *//}

例:

#include <stdio.h>
namespace First
{
      int i = 0;
}
namespace Second
{
      int i = 1;   
      namespace Internal
      {
          struct P
          {
               int x;
               int y;
          };
      }
}
int main(int argc, char *argv[])
{
    ......
} //连个同名全局变量i,因为他们位于不同的命名空间里面,没有发生冲突,C++编译器看到他们位于不同命名空间后,就认为肯定是可以区分他们的,所以编译通过


C++命名空间的使用:

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

—使用命名空间中的变量:using name::varible;

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

默认情况下可直接使用默认命名空间中的所有标示符

例:

#include <stdio.h>
namespace First
{
    int i = 0;
}
namespace Second
{
    int i = 1;    
    namespace Internal
    {
        struct P
        {
            int x;
            int y;
        };
    }
}

int main(int argc, char *argv[])
{
    using namespace First;      //使用First这个命名空间里面的所有标示符,可以直接访问 
    using Second::Internal::P;   //使用Second这个命名空间里面内嵌的Interal这个命名空间里面的P标示符 
    
    printf("i = %d\n",i);     //此处i是First里面的i,因为First被完全打开,其中变量可直接访问 ,输出0 
    printf("i = %d\n",Second::i);    //访问Second空间里面的i,由于Second没有被打开,里面的变量没有被完全释放,所以必须指定的访问里面的某个变量才行,输出1 
    
    P p = {2,3};  //P已经释放出来,可直接访问
    
    printf("p.x = %d\n",p.x);   //输出2 
    printf("p.y = %d\n",p.y);   //输出3 
    ......
}

    

强制类型转换

C方式的强制类型转换

(Type)(Expression) or Type(Expression)

烂程序示例:test.cpp

typedef void(PF)(int);
struct Point
{
    int x;
    int y;
};
int main(int argc, char *argv[])
{
    int v = 0x12345;
    PF* pf = (PF*)v;
    char c = char(v);   
    pf(v);   
    Point* p = (Point*)v;    
    printf("p->x = %d\n",p->x);
    printf("p->y = %d\n",p->y);
    ......
}  //C++编译器可编译通过,但是不能运行


C方式强制类型转换存在的问题

—过于粗暴

    —-任意类型之间都可以进行转换,编译器很难判断其正确性 

// 现代软件工程中3大问题是bug的来源:

// 1.运算符优先级:当位运算,逻辑运算和数学运算混合在一起时,优先级对不对;

// 2.多线程编程时各个线程间的交互;

// 3.强制类型转换

—难于定位

    —-在源码中无法快速定位所有使用强制类型转换的语句

在程序设计理论中强制类型转换是不被推荐的,与goto语句一样,应该尽量避免


强制类型转换在实际工程中还是可能使用的

如火如荼进行更加安全可靠的转换?

C++将强制类型转换分成4中不同的类型


用法:xxx_cast<Type>(Expression)


static_cast强制类型转换

——用于基本类型间的转换,但不能用于基本类型指针见的转换

——用于有继承关系类对象之间的转换和类指针之间的转换

int main(int argc, char *argv[])
{
    int i = 0;
    char c = 'c';
    int* pi = &i;
    char* pc = &c;
    
    c = static_cast<char>(i); //It's OK!
    pc = static_cast<char*>(pi); //Oops!   invalid static_cast from type 'int*' to type 'char*'
    ......
}

static_cast是编译期进行转换的,无法在运行时检测类型,所以类型转换之间的转换可能存在风险。


const_cast强制类型转换

——用于去除变量的const属性

int main(int argc, char *argv[])
{
    const int& j = 1;
    int& k = const_cast<int&>(j);  //将只读变量j降级为普通变量,k是j的引用,改变k就是改变j
    const int x = 2;   //常量x
    int& y = const_cast<int&>(x); //常量x在强制类型转换为应用后,C++编译器给他分配了空间,引用y就是所分配空间的别名
    
    k = 5;
    
    printf("j = %d\n",j);   //输出5
    printf("k = %d\n",k); //输出5
    
    y = 3;
    
    printf("x = %d\n",x);  //输出2  ,直接从符号表中拿
    printf("y = %d\n",y);  //输出3
    printf("&x = %p\n",&x); //输出0022FF0C
    printf("&y = %p\n",&y); //输出0022FF0C  x和y地址完全一样
    
    printf("Press enter to continue ...");
    getchar();
    return 0;
}


reinterpret_cast强制类型转换

——用于指针类型间的强制换行

——用于整数和指针类型间的强制转换

typedef void(PF)(int);
int main(int argc, char *argv[])
{
    int i = 0;
    char c = 'c';
    int* pi = reinterpret_cast<int*>(&c);
    char* pc = reinterpret_cast<char*>(&i);
    PF* pf = reinterpret_cast<PF*>(0x12345678);
    
    c = reinterpret_cast<char>(i); //Oops  static_cast should be used here
    ......
}

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


dynamic_cast强制类型转换

——主要用于类层次间的转换,还可以用于类之间的交叉转换

——dynamic_cast具有类型检查功能,比static_cast更安全


小结

C++中内置了动态内存分配的专用关键字

C++中的动态内存分配是基于类型进行的

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

C++细化了C语言中强制类型转换的方式

——C++不推荐的程序中使用强制类型转换

——C++建议在强制类型是考虑一下究竟希望什么样的转换

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值