• C++对C的扩展、增强


    C++对C的扩展

    1. 双冒号::作用域运算符

    代码中对同一个变量多次声明,在代码块中使用时,局部变量会将全局变量隐藏。若在代码块使用变量前添加::,表示为全局变量。

    ::表示作用域运算符,如常见的std::cout,std::endl;等,表示cout和endl是std作用域下的标识符。

    2. 命名空间namespace

    主要用来解决命名冲突的问题,如多个人开发的不同模块中使用了相同的变量名和函数名,fatal error LNK1169:找到一个或多个重定义的符号,这时可以使用命名空间,将不同的模块分隔开。

    1 namespace QGY{
    2     int a;
    3     void test();
    4     struct QGYTEST{
    5         int b;
    6     };
    7     class QGYNUM{};
    8 }

    使用命名空间的注意事项:(1)必须在全局作用域下声明;(2)命名空间下可以放函数,变量、结构体和类;(3)命名空间可以嵌套命名空间;(4)命名空间是开放的,可以随时加入新成员(添加时只需要再次声明namespace,然后添加新成员即可,示例如下);(5)无名或匿名命名空间,相当于static变量;(6)可以对命名空间起别名(一般不用)

    namespace QGY{
    	int m ;
    }

    3. using声明和using编译指令

    using QGY::a; //声明
    using namespace QGY; //编译指令

    对于声明来说,如果局部范围内还有a,会出现二义性,程序不知道使用哪一个,因此应避免这种情况.

    1 void test01(){
    2     int a = 10;
    3     using QGY::a; //这里在声明的时候不能进行赋值,可以在下一行,a = 20;
    4     std::cout << a << std::endl;
    5 }

    这里程序会出现错误, error C2874: using 声明导致“QGY::a”的多次声明。

    对于编译指令,如果局部范围还有a,会使用局部变量。如果还有另外的命名空间也声明了a,且同时打开了其他空间,则也会出现二义性。

    1 void test02(){
    2     int a = 10;
    3     using namespace QGY; //这里只是打开空间,并没有指定使用
    4     std::cout << a << std::endl;
    5 }
    1 void test03(){
    2     using namespace QGY; //只是打开房间就可以访问到a,打开多个房间就会产生二义性
    3     std::cout << a << std::endl;
    4 }

    C++对C的增强

     1.全局变量检测增强

    C语言会忽略对全局变量重定义的检测,但不会忽略对局部变量的检测,C++中都会报错:error C2086: “int a”: 重定义

    //全局变量不会报错
    int a;
    int a = 10;
    
    //局部变量会报错
    void test(){
    	int a;
    	int a = 10;
    }
    

    2.函数检测增强:包括函数形参类型检测,形参数目检测,函数返回值检测,C都会忽略,C++不会

    1 //C中函数形参没有参数类型,没有返回值,调用参数过多都会忽略
    2 int test(m, n){
    3 
    4 }
    5 
    6 void test01(){
    7     test(1,2,3);
    8 }

     3.类型转换检测增强

    C语言中malloc开辟内存空间时默认生成void*指针,可以转换成任意指针,C++中则不行,必须显式的进行强制转换。

    4.struct增强

    (1)C中strcut中不能有函数,C++中可以有,并且与class的区别在于是否有私有成员,和是否有构造函数;

    (2)通过如下方式声明struct时,C语言定义使用结构体时必须使用struct,C++可以不用。

    1 struct Person{
    2     int a;
    3 };
    4 
    5 struct Person myperson; //C
    6 Person myperson; //C++

    5.bool类型增强

    C语言中没有bool类型,C++中有bool类型,其中sizeof(bool)=1

    6.三目运算符增强

     1 a > b?a : b; 

    C语言中返回的是值,C++中返回的是变量,C语言中下面代码会报错:error C2106: “=”: 左操作数必须为左值,表明代码中为20=100,所以会报错。

    1 void test01(){
    2     int a = 10;
    3     int b = 20;
    4     printf("%d
    ", a > b? a:b);
    5     a > b ? a : b = 100; 
    6 }

    如果想改变三目运算符后的结果,可以按照如下代码进行修改

     1 *(a > b? &a:&b) = 100; 

    C++则不会,因为C++三目运算后为变量,因此可以进行赋值操作,其中a  = 10, b = 100;

    1 void test01(){
    2     int a = 10;
    3     int b = 20;
    4     a > b ? a : b = 100;
    5     cout << a << " " << b << endl;
    6 }

    另外下面三种情况下的a和b的值是不同的

    1 //a=100, b=20
    2 (a < b ? a : b) = 100;
    3 
    4 //a=10, b=100
    5 (a > b ? a : b) = 100;
    6 
    7 //a=10, b=20
    8 a < b ? a : b = 100;

    最后一种情况,不会执行b=100,其中带括号的是按照我们的想法去执行代码,不带括号的话,优先级不同导致结果和预想的不同。

    7.const增强

    (1)是否可以修改

    C语言中的全局const不可修改,是真常量,如果对其修改会出现访问冲突,另外不可以声明数组的大小(这是C的缺陷,也是为什么替代不了define);局部const为伪常量,可以进行修改,同时不可以用于声明数组的大小(真假都不可以声明数组的大小)。

    1 const int m = 0; //全局静态变量受到保护,不可修改
    2 void test01(){
    3     const int n = 1; //伪常量,可以通过地址进行修改
    4     int *p = &n; //可以不加强制转换
    5     *p = 100;
    6     printf("%d
    ", n);
    7 
    8     int am[n]; //n不可用于声明大小,不是常量值
    9 }

    C++不管全局还是局部都是真常量,不可修改,同时可以初始化数组,原因如下(取地址时会分配临时内存):

    (2)链接属性

    C语言的const默认是外部链接,C++默认是内部链接

    1 //1.cpp
    2 const int a = 10; 
    3 
    4 //2.cpp
    5 extern const int a;

    C语言中进行访问时可以的,但C++中需要在1.cpp的声明前加extern否则无法使用

    (3)const分配内存

    是否分配内存,我们可以根据const修饰的变量是否能够修改来确定。

    编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高,但是在下列几种情况下编译器会为const定义的常量分配内存的。

    (3.1)取地址时,const会分配临时内存,不可以进行间接修改

    1 void test003(){
    2     const int m = 10;
    3     int *p = (int *)&m;//分配临时内存,不可以进行间接修改
    4     *p = 100;
    5     cout << m << endl;
    6 }

    (3.2)extern编译器也会为变量分配内存

    因为使用了extern,我们将可能在外部文件使用该变量,而const默认的是内部链接,所以我们必须要为之分配内存的。

    (3.3)用普通变量初始化const变量,会分配内存

    1 void test003(){
    2     int m = 10;
    3     const int b = (int *)&m; //分配内存,且可以跳过编译器检测进行间接修改,另外需要加强制转换
    4     int *p = &b;
    5     *p = 100;
    6 }

    (3.4)自定义数据,加const也会分配内存

     1 struct Person{
     2     int age;
     3 };
     4 
     5 void test004(){
     6     const Person person = {10};//分配内存,且可以跳过编译器检测进行间接修改
     7     
     8     Person *b = (Person*)&person; 
     9     (*b).age = 20;
    10     cout << (*b).age << endl;
    11 }

     (4)尽量用const替换define

    对于常量,尽量替换因为const有数据类型检查和作用域。另外define用于宏定义时,可以用undef进行解除。但是对于有些条件编译时需要define,则不能替换。

    define是应用于预处理的,而const是在编译的时候处理的。对于单纯常量,使用const与enum代替宏,对于函数形式的宏,则使用inline与template替代。

  • 相关阅读:
    编译错误总结。
    9.7
    9.5
    9.6
    9.4
    9.3
    FutureTask取结果超时代码小测试
    java concurrent包常用类小结
    java Nio零散知识点整理
    java进阶教程unit_2java常用类(2)
  • 原文地址:https://www.cnblogs.com/qinguoyi/p/10204893.html
Copyright © 2020-2023  润新知