首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

c++学习笔记(4.c++中新的关键字)

c++学习笔记(4.c++中新的关键字)

本节知识点:1.关键字new与delete:   a.c++中通过new关键字进行动态内存分配,new是一种基于类型进行的内存分配,同时c++使用delete进行内存释放
      单个变量内存申请与释放:Type* p = new Type;           delete   p;
      一段内存空间的申请与释放:Type* p = new Type [N];           delete  []   p;     
      示例代码如下:
[cpp] view plaincopy


  • #include <stdio.h>
  • #include <malloc.h>
  • int main()  
  • {  
  •     /*使用new申请单个变量*/
  •     double* p = new
    double;   
  •     *p = 7.2;   
  •     printf("%f\n",*p);  
  •     delete p;  

  •     int *p1 = (int*)malloc(sizeof(int)*10);  
  •     for(int i = 0; i < 10; i++)  
  •     {  
  •         *(p1+i) = i;  
  •     }   
  •     for(int i = 0; i < 10; i++)  
  •     {  
  •         printf("%d\n",p1);  
  •     }   
  •     free(p1);  

  •     /*使用new申请一段连续的内存空间*/
  •     //new出来的这个空间看着像数组 但它跟数组有本质区别  这是在堆区的
  •     int *p2 = new
    int[10];     
  •     for(int i = 10; i > 0; i--)  
  •     {  
  •         p2[10-i] = i;  
  •     }  
  •     for(int i = 0; i < 10; i++)  
  •     {  
  •         printf("%d\n",*(p2+i));  
  •     }  
  •     delete [] p2;  
  •     return 0;  
  • }   

   b.new关键字与malloc函数的区别:

      第一:new关键字是c++的一部分,而malloc是由c库提供的函数
      第二:new是以具体类型为单位进行内存分配,malloc只能以字节为单位进行内存分配
      第三:new在申请单个类型变量时可进行初始化,malloc不具备内存初始化的特性,代码如下:

[cpp] view plaincopy


  • #include <stdio.h>
  • int main()  
  • {  
  •     int* p = new
    int(6);  
  •     printf("%d\n",*p);  

  •     double* fp = new
    double(7.2);  
  •     printf("%f\n",*fp);  

  •     char* cp = new
    char('d');  
  •     printf("%c\n",*cp);  

  •     return 0;  
  • }   

2.c++中的命名空间:    a.命名空间产生的原因:在c语言中只有一个全局作用区,所有的全局标识符(包括全局变量、函数)共享同一个全局作用区。尽管有static关键字的限制,但是在工程中依然存在接口函数名之间,或与库函数名冲突的现象。所以c++中提出了命名空间的概念,命名空间将全局作用区分成了若干的命名空间无名空间(即默认空间,也就是兼容c语言的全局作用区的空间)。

    b.命名空间的有效作用域:在c语言中没有命名空间的概念,导致所有在全局作用区的全局标识符的作用域都是,从这个变量或者函数定义声明开始一直有效到程序结束(从始至终贯穿着整个程序,所有很容易就冲突了)。而c++中有了命名空间的概念后,一旦在一个函数中使用using namespace name1;    using name1::a;这样的语句的时候,name1这个命名空间的作用域和name1中a变量的作用域,就是从using命令开始到这个函数结束(也就是说可以通过命名空间来控制全局变量的作用域了)。如果是在一个命名空间name2中使用using命令的话,那name1和a的作用域就属于name2了(即与name2属于相同作用域)。如果在默认命名空间(无名空间)中使用using命令,name1和a的作用域就变化与c语言一样的那个全局作用区了。如果使用name1::a这样方法直接去控制变量的话,那作用域就是使用瞬间。
     c.命名空间的语法:
        定义命名空间(要在函数外面定义):
[cpp] view plaincopy


  • namespace name2   //这个是命名空间的嵌套
  • {  
  •     int c = 2;  
  •     int f = 5;  
  •     namespace name3  
  •     {  
  •         int d = 3;   
  •         int e = 4;  
  •     }  
  • }  

          使用命名空间(有三种方式):

           第一:using spacename name1;  开启name1这个命名空间,可以使用这个命名空间中的所有变量了。
           第二:using name1::a;   可以使用name1命名空间中的a变量了。
           第三:name1::a = 10;   直接使用name1命名空间的a变量
           第四:::a = 10; 或者  a = 10;    直接使用默认命名空间中的变量
       d.使用命名空间要注意:
           第一:命名空间是可以相互嵌套的,且有一个嵌套顺序的问题,不同嵌套顺序的命名空间,即使名称相同,也是不同的命名空间。因为using的时候,是有顺序的。
           第二:相同名称的命名空间,在using的时候,两个命名空间都会被打开。只要相同名称的命名空间中没有同名变量就可以!否则在使用这个变量的时候,就会出现二义性,编译会出问题。
           第三:不同命名空间中,标识符可以同名而不会发生冲突!因为在使用的时候,不一定会同时using这两个命名空间,所以不一定会产生二义性!但是如果同时打开这两个命名空间,还去使用了这个同名变量,编译也会出错,因为产生二义性!但是当using spacename name1;(name1中有变量a)  并且using name2::a的时候,再使用a变量的时候就没有二义性了,编译器默认选择name2中的a变量使用。代码如下:
[cpp] view plaincopy


  • #include<stdio.h>

  • namespace name1  
  • {  
  •     int a = 9;  
  •     namespace name1  
  •     {  
  •         int a = 10;   
  •     }  
  • }  
  • namespace name2  
  • {  
  •     int p = 19;  
  •     int a = 0;   
  • }  

  • int  main()  
  • {  
  •     using
    namespace name1;  
  •     using name2::a;  
  •     printf("%d\n",a);  
  •     return 0;  
  • }   

3.c++中的强制类型转换:    a.c语言中的强制类型转换:有两种方式,(Type) name     和   Type (name)  注意第二种方式不是很常用。

    b.c语言中强制类型转换存在的问题:
       第一:过于粗暴,任何类型之间都可以进行转换,编译器很难判断其正确性。
       第二:难于定位,在源码中无法快速定位所有使用强制类型转换的语句。
       补充:在程序设计理论中强制类型转换不被推荐,与goto语句一样,应该进行避免,因为在程序设计过程中,定义变量就应该清楚变量的使用环境,直接定义成有效的类型,避免强制类型转换。还有就是现代的软件产品里面有三个问题是bug的源泉:有运算符的优先级问题、多线程编程中各个线程的交互、强制类型转换。
    c.c++中将强制类型转换分成四个类型:
       static_cast类型:用于基本类型间的转换,但不能用于指针类型间的转换。用于有继承关系对象之间的转换和类指针之间的转换但是static_cast是编译期进行的转换,无法在运行时检测类型,所以类类型之间的转换可能存在风险。代码如下:
[cpp] view plaincopy


  • #include <stdio.h>
  • int main()  
  • {  
  •     int a = 99;  
  •     double b = static_cast<double>(a);  
  •     printf("%f\n",b);  

  •     printf("%c\n",static_cast<char>(b));  
  •     getchar();  
  •     return 0;  
  • }  


        const_cast类型:用于去除变量的const属性,注意,它只能去除const int* p或者const int& p这两种类型中的const属性。比如int* const p类型中的const属性是去不掉的,其实不管用什么手段这个const的属性都是去不掉的,int* const p = &a;  p一旦指向就不能再改变指向,这其实就是引用的实质!!!
        const_cast类型有三个常用环境:第一,去除const int &j;的const只读属性、第二,去除const int * j;的const只读属性、第三,去除const int j;的const只读属性。代码如下:[cpp] view plaincopy


  • #include <stdio.h>
  • int main()  
  • {  
  • /*const int &j  去除const属性*/
  •     const
    int& j = 4;  
  •     const_cast<int&>(j) = 6;  //其实实际上j就是一个只读变量 利用指针也可以改变j的值的
  •   //    *(int*)(&j) = 6;  //这步的强制类型转换与上面那句代码等效
  •     printf("j is %d\n",j);   
  •     int& i = const_cast<int&>(j);   
  •     i = 12;  
  •     printf("j is %d\n",i);  

  • /*const int* p 去除const属性*/
  •     int a = 1;  
  •     const
    int* p = &a;  
  •     *const_cast<int*>(p) = 2;  
  •   //    *(int* )p = 2; //与上面代码等效的强制类型转换
  •     printf("*p is %d\n",*p);  

  • /*const int l = 6*/
  •     const
    int l = 16;  
  •     const_cast<int&>(l) = 17;  
  •   //    (int&)l = 17;  //与上面语句等效的强制类型转换
  •   //    *const_cast<int*>(&l) = 17;
  •   //    *(int*)&l = 17;
  •     printf("l is %d\n",l);   
  •     return 0;  
  • }  

对于上面代码有两点要说明:

第一:const_cast其实只读const指针和const引用起作用了,对const常量没有起作用,因为const常量是保存在符号表中的。
第二:对于引用的强制类型转换,int a = 10;  (char)a这是将a变量中的值强制类型转换成char类型,切记此时(char)a不是变量不能当做左值使用。但是(char&)a是将a强制类型转换成char类型的引用,其实是一个变量可以当做左值使用!对于const_cast<int&>(l) = 17; 来说l常量是存放在符号表中的,而const_cast<int&>(l)其实是个有内存空间的变量,其实相当于对l取地址的时候,编译器分配了一个内存空间,这个空间不是用来存放l常量的,而是强制类型转换后这个引用的内存空间,所以说这个17就存放在这个引用的内存空间了!!!
           reinterpret_cast类型:用于指针类型间的强制类型转换,用于整数和指针间的强制类型转换,还用于引用间的强制类型转换。(注:此处指针引用的强制类型转换都是没有const属性去除过程的,否则优先使用const_cast)
           引用间的强制类型转换(代码如下):

[cpp] view plaincopy


  • #include <stdio.h>
  • int main()  
  • {  
  •     int a = 10;  
  •     int &b = a;  
  •     char &c = reinterpret_cast<char&>(b);  
  •     printf("%d\n",reinterpret_cast<char&>(b));  
  •     a = 129;  
  •     printf("a is %d\n",a);  
  •     printf("b is %d\n",b);  
  •     printf("c is %d\n",c);  
  •     return 0;  
  • }  

              我们仔细说说代码中c引用与b引用的关系,不可否定的是abc三个变量,有其中任何一个变量改变了,都会对另外的两个起到改变的作用!a与b仅仅是名字不同的问题(其余完全相同),但是c引用是与b引用变成char类型引用变量后完全相同的。

               reinterpret_cast类型用法,代码如下:
[cpp] view plaincopy


  • #include <stdio.h>
  • int main()  
  • {  
  •     int a = 10;  
  •     *reinterpret_cast<unsigned int*>(&a) = 12;   
  •     printf("a is %d\n",a);  
  •     int* b = &a;  
  •     char* c = reinterpret_cast<char*>(b);  
  •     *c = 14;  
  •     printf("a is %d\n",*c);  
  •     return 0;  
  • }  

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

       dynamic_cast类型:主要用于类层次间的转换,还可以用于类之间的交叉转换。dymanic_cast具有类型检查的功能,比static_cast更安全。这个问题等对类有了理解再回来补充。
返回列表