• 【C/C++】C编程技巧


    目录

    1. 关键字const

    2. 关键字default

    3. 关键字explicit


    1. 关键字const

    const是一个C语言(ANSI C)的关键字,具有着举足轻重的地位。它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。

    与预编译指令“例如#define”相比,const修饰符有以下的优点:

    1、预编译指令只是对值进行简单的替换,不能进行类型检查

    2、可以保护被修饰的东西,防止意外修改,增强程序的健壮性

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

    下面我们从几个方面来说一下const的用法:

    一、修饰局部变量

    1. const int Max=100;
    2. Max++; //会产生错误

    二、可以节省空间,避免不必要的内存分配。 例如:

    1

    2

    3

    4

    5

    6

    #define PI 3.14159 //常量宏

    const double Pi=3.14159; //此时并未将Pi放入ROM中 ......

    double i=Pi; //此时为Pi分配内存,以后不再分配!

    double I=PI; //编译期间进行宏替换,分配内存

    double j=Pi; //没有内存分配

    double J=PI; //再进行宏替换,又一次分配内存!

    const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝。 

    全局变量的作用域是整个文件,我们应该尽量避免使用全局变量,因为一旦有一个函数改变了全局变量的值,它也会影响到其他引用这个变量的函数,导致除了bug后很难发现,如果一定要用全局变量,我们应该尽量的使用const修饰符进行修饰,这样防止不必要的人为修改,使用的方法与局部变量是相同的。

    三、在C++中,定义指针要指向地址

    必须初始化指针的指向int* const px = &x;const int* const px=&x;

    强烈建议在初始化时说明指针的指向,防止出现野指针!

    四、如果想在多个文件之间共享const对象,必须在变量的定义之前添加extern关键字。

    2. 关键字default

    如果default语句在所有case最后,此时可以不加break 如果default语句之后还有case语句,如果不加break,则default语句执行过之后会继续下面的case语句,此时必须要在default之后加break语句,不过这种default用法是不推荐的,default顾名思义是缺省情况,只有任何条件都不匹配的情况下才会执行,所以应该将default语句放在所有case结束之后。

    1. switch(表达式)
    2. {
    3. case 常量表达式1: 语句1;break;
    4. case 常量表达式2: 语句2;break;
    5. case 常量表达式3: 语句3;break;
    6. default: 语句n+1;break;
    7. }

    3. 关键字explicit

    ————————————————
    版权声明:本文为CSDN博主「流楚丶格念」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_45525272/article/details/105996548 

    C++中的explicit关键字只能用于修饰只有一个参数的类构造函数, 它的作用是表明该构造函数是显示的, 而非隐式的, 跟它相对应的另一个关键字是implicit, 意思是隐藏的,类构造函数默认情况下即声明为implicit(隐式)。

    那么显示声明的构造函数和隐式声明的有什么区别呢?

    1. class CxString // 没有使用explicit关键字的类声明, 即默认为隐式声明
    2. {
    3. public:
    4. char *_pstr;
    5. int _size;
    6. CxString(int size)
    7. {
    8. _size = size; // string的预设大小
    9. _pstr = malloc(size + 1); // 分配string的内存
    10. memset(_pstr, 0, size + 1);
    11. }
    12. CxString(const char *p)
    13. {
    14. int size = strlen(p);
    15. _pstr = malloc(size + 1); // 分配string的内存
    16. strcpy(_pstr, p); // 复制字符串
    17. _size = strlen(_pstr);
    18. }
    19. };
    20. // 下面是调用:
    21. CxString string1(24); // 这样是OK的, 为CxString预分配24字节的大小的内存
    22. CxString string2 = 10; // 这样是OK的, 为CxString预分配10字节的大小的内存
    23. CxString string3; // 这样是不行的, 因为没有默认构造函数, 错误为: “CxString”: 没有合适的默认构造函数可用
    24. CxString string4("aaaa"); // 这样是OK的
    25. CxString string5 = "bbb"; // 这样也是OK的, 调用的是CxString(const char *p)
    26. CxString string6 = 'c'; // 这样也是OK的, 其实调用的是CxString(int size), 且size等于'c'的ascii码
    27. string1 = 2; // 这样也是OK的, 为CxString预分配2字节的大小的内存
    28. string2 = 3; // 这样也是OK的, 为CxString预分配3字节的大小的内存
    29. string3 = string1; // 这样也是OK的, 至少编译是没问题的, 但是如果析构函数里用

     “CxString string2 = 10;” 这句为什么是可以的呢?

    在C++中, 如果的构造函数只有一个参数时, 那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象。 也就是说 “CxString string2 = 10;” 这段代码, 编译器自动将整型转换为CxString类对象, 实际上等同于下面的操作: CxString string2(10)。

    但是, 上面的代码中的_size代表的是字符串内存分配的大小, 那么调用的第二句 “CxString string2 = 10;” 和第六句 “CxString string6 = ‘c’;” 就显得不伦不类, 而且容易让人疑惑. 有什么办法阻止这种用法呢? 答案就是使用explicit关键字. 我们把上面的代码修改一下, 如下:

    1. class CxString // 使用关键字explicit的类声明, 显示转换
    2. {
    3. public:
    4. char *_pstr;
    5. int _size;
    6. explicit CxString(int size)
    7. {
    8. _size = size;
    9. // 代码同上, 省略...
    10. }
    11. CxString(const char *p)
    12. {
    13. // 代码同上, 省略...
    14. }
    15. };
    16. // 下面是调用:
    17. CxString string1(24); // 这样是OK的
    18. CxString string2 = 10; // 这样是不行的, 因为explicit关键字取消了隐式转换
    19. CxString string3; // 这样是不行的, 因为没有默认构造函数
    20. CxString string4("aaaa"); // 这样是OK的
    21. CxString string5 = "bbb"; // 这样也是OK的, 调用的是CxString(const char *p)
    22. CxString string6 = 'c'; // 这样是不行的, 其实调用的是CxString(int size), 且size等于'c'的ascii码, 但explicit关键字取消了隐式转换
    23. string1 = 2; // 这样也是不行的, 因为取消了隐式转换
    24. string2 = 3; // 这样也是不行的, 因为取消了隐式转换
    25. string3 = string1; // 这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载

    explicit关键字的作用就是防止类构造函数的隐式自动转换

    上面也已经说过了, explicit关键字只对有一个参数的类构造函数有效,如果类构造函数参数大于或等于两个时, 是不会产生隐式转换的, 所以explicit关键字也就无效了。例如:

    1. class CxString // explicit关键字在类构造函数参数大于或等于两个时无效
    2. {
    3. public:
    4. char *_pstr;
    5. int _age;
    6. int _size;
    7. explicit CxString(int age, int size)
    8. {
    9. _age = age;
    10. _size = size;
    11. // 代码同上, 省略...
    12. }
    13. CxString(const char *p)
    14. {
    15. // 代码同上, 省略...
    16. }
    17. };
    18. // 这个时候有没有explicit关键字都是一样的

    但是, 也有一个例外, 就是当除了第一个参数以外的其他参数都有默认值的时候, explicit关键字依然有效, 此时, 当调用构造函数时只传入一个参数, 等效于只有一个参数的类构造函数, 例子如下:

    1. class CxString // 使用关键字explicit声明
    2. {
    3. public:
    4. int _age;
    5. int _size;
    6. explicit CxString(int age, int size = 0)
    7. {
    8. _age = age;
    9. _size = size;
    10. // 代码同上, 省略...
    11. }
    12. CxString(const char *p)
    13. {
    14. // 代码同上, 省略...
    15. }
    16. };
    17. // 下面是调用:
    18. CxString string1(24); // 这样是OK的
    19. CxString string2 = 10; // 这样是不行的, 因为explicit关键字取消了隐式转换
    20. CxString string3; // 这样是不行的, 因为没有默认构造函数
    21. string1 = 2; // 这样也是不行的, 因为取消了隐式转换
    22. string2 = 3; // 这样也是不行的, 因为取消了隐式转换
    23. string3 = string1; // 这样也是不行的, 因为取消了隐式转换, 除非类实现操作符"="的重载

    总结:
    explicit关键字只需用于类内单参数构造函数前面。由于无参数的构造函数多参数的构造函数总是显示调用,这种情况在构造函数前加explicit无意义。

    google的c++规范中提到explicit的优点是可以避免不合时宜的类型变换,缺点无。所以google约定所有单参数的构造函数都必须是显示的,只有极少数情况下拷贝构造函数可以不声明称explicit。例如作为其他类的透明包装器的类。
      effective c++中说:被声明为explicit的构造函数通常比其non-explicit兄弟更受欢迎。因为它们禁止编译器执行非预期(往往也不被期望)的类型转换。除非我有一个好理由允许构造函数被用于隐式类型转换,否则我会把它声明为explicit,鼓励大家遵循相同的政策。

  • 相关阅读:
    背包问题温习
    PIC单片机5——串口 中断
    降本增效两不误——云原生赋能航空业数字化转型
    STM32F103标准库开发---SPI实验---底层驱动程序
    使用React 18和WebSocket构建实时通信功能
    视觉与机器人的九点标定(一)
    【MySQL进阶】深入理解InnoDB数据页结构
    【JAVA-1】EditPlus安装及配置,有手就会!
    算法通关村-----链表中环的问题
    优雅的实现EasyPoi动态导出列的两种方式
  • 原文地址:https://blog.csdn.net/Roger_717/article/details/126298419