• 高质量C++/C 编程指南一


    首先,强烈推荐林锐博士这本《高质量C++/C 编程指南》,请花一两个小时认真阅读这本百页经书,你将会获益匪浅。草草看过,个人收获记录如下。
    头文件的作用略作解释:
    (1)通过头文件来调用库功能。在很多场合,源代码不便(或不准)向用户公布,只要向用户提供头文件和二进制的库即可。用户只需要按照头文件中的接口声明来调用库功能,而不必关心接口怎么实现的。编译器会从库中提取相应的代码。
    (2)头文件能加强类型安全检查。如果某个接口被实现或被使用时,其方式与头文件中的声明不一致,编译器就会指出错误,这一简单的规则能大大减轻程序员调试、改错的负担。
    另:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义。如果函数的声明中带有关键字extern,仅仅是暗示这个函数可能在别的源文件里定义,没有其它作用。
    空行
    a.在每个类声明之后、每个函数定义结束之后都要加空行。
    b.在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。(这一条值得注意)
    代码行
    a.一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。
    b.if、for、while、do 等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加{}。这样可以防止书写失误。

    for(initalization;contition;update)
    
    {
        dosomething();
    }
    //空行
    other();

    c.尽可能在定义变量的同时初始化该变量(就近原则)
    代码行内的空格
    a.关键字后要留空格,如const、virtual、inline、case以及if、for、while;函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。
    b.逗号与分号之后要留空格;“=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格一元操作符前后不加空格
    c.象“[]”、“.”、“->”这类操作符前后不加空格。
    d.对于表达式比较长的for 语句和if 语句,为了紧凑起见可以适当地去掉一些空格。

    for (i=0; i<10; i++) // 良好的风格

    长行拆分
    代码行最大长度宜控制在70 至80 个字符以内。长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。

    if ((very_longer_variable1 >= very_longer_variable12)
        && (very_longer_variable3 <= very_longer_variable14)
        && (very_longer_variable5 <= very_longer_variable16))
    {
        dosomething();
    }

    注释
    a.注释是对代码的“提示”,而不是文档。程序中的注释不可喧宾夺主,注释太多了会让人眼花缭乱。注释的花样要少。
    b.边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。
    c.尽量避免在注释中使用缩写,特别是不常用缩写。
    d.注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不可放在下方。
    f.当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。
    类的版式
    类的版式主要有两种方式:
    (1)将private 类型的数据写在前面,而将public 类型的函数写在后面。采用这种版式的程序员主张类的设计“以数据为中心”,重点关注类的内部结构。
    (2)将public 类型的函数写在前面,而将private 类型的数据写在后面。采用这种版式的程序员主张类的设计“以行为为中心”,重点关注的是类应该提供什么样的接口(或服务)。
    建议读者采用“以行为为中心”的书写方式,即首先考虑类应该提供什么样的函数。

    class A
    {
        public:
            void Func1(void);
            void Func2(void);
            …
        private:
            int i, j;
            float x, y;
            …
    }

    共性规则
    a.标识符应当直观且可以拼读,可望文知意;标识符的长度应当符合“min-length && max-information”原则。
    b.命名规则尽量与所采用的操作系统或开发工具的风格保持一致。
    例如 Windows 应用程序的标识符通常采用“大小写”混排的方式,如AddChild。而Unix 应用程序的标识符通常采用“小写加下划线”的方式,如add_child。别把这两类风格混在一起使用。
    c.变量的名字应当使用“名词”或者“形容词+名词”;全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。
    d.尽量避免名字中出现数字编号,如Value1,Value2 等,除非逻辑上的确需要编号。这是为了防止程序员偷懒,不肯为命名动脑筋而导致产生无意义的名字(因为用数字编号最省事)。
    简单的Windows 应用程序命名规则
    a.类名和函数名用大写字母开头的单词组合而成
    b.变量和参数用小写字母开头的单词组合而成。
    c.常量全用大写的字母,用下划线分割单词。
    d.静态变量加前缀s_(表示static)。
    e.如果不得已需要全局变量,则使全局变量加前缀g_(表示global)。
    f.类的数据成员加前缀m_(表示member),这样可以避免数据成员与成员函数的参数同名。
    g.为了防止某一软件库中的一些标识符和其它软件库中的冲突,可以为各种标识符加上能反映软件性质的前缀。
    if语句
    不可将浮点变量用“==”或“!=”与任何数字比较。

    if ((x >= -EPSINON) && (x <= EPSINON))
    //其中EPSINON 是允许的误差(即精度)。

    有时候我们可能会看到 if (NULL == p) 这样古怪的格式。不是程序写错了,是程序员为了防止将 if (p == NULL) 误写成 if (p = NULL),而有意把p 和NULL 颠倒。编译器认为 if (p = NULL) 是合法的,但是会指出 if (NULL = p)是错误的,因为NULL不能被赋值。
    程序中有时会遇到 if/else/return 的组合,应该将如下不良风格的程序

    if (condition)
        return x;
    return y;

    改写为

    if (condition)
    {
        return x;
    }
    else
    {
        return y;
    }

    或者改写成更加简练的

    return (condition ? x : y);

    循环语句的效率
    C++/C 循环语句中,for 语句使用频率最高,while 语句其次,do 语句很少用。提高循环体效率的基本办法是降低循环体的复杂性。
    在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU 跨切循环层的次数。
    switch 语句
    不要忘记最后那个default 分支。即使程序真的不需要default 处理,也应该保留语句 default : break; 这样做并非多此一举,而是为了防止别人误以为你忘了default 处理。
    goto 语句
    我们主张少用、慎用goto 语句,而不是禁用。
    const 与 #define 的比较
    C++ 语言可以用const 来定义常量,也可以用 #define 来定义常量。但是前者比后者有更多的优点:
    (1)const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应)。
    (2)有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。
    建议:在C++ 程序中只使用const 常量而不使用宏常量。
    类中的常量
    有时我们希望某些常量只在类中有效。由于#define 定义的宏常量是全局的,不能达到目的,于是想当然地觉得应该用const 修饰数据成员来实现。const 数据成员的确是存在的,但其含义却不是我们所期望的。const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其const 数据成员的值可以不同。不能在类声明中初始化const 数据成员。以下用法是错误的,因为类的对象未被创建时,编译器不知道SIZE 的值是什么。

    class A
    {
        …
        const int SIZE = 100; // 错误,企图在类声明中初始化const 数据成员
        int array[SIZE]; // 错误,未知的SIZE
    };

    const 数据成员的初始化只能在类构造函数的初始化表中进行,例如

    class A
    {
        …
        A(int size); // 构造函数
        const int SIZE ;
    };
    A::A(int size) : SIZE(size) // 构造函数的初始化表
    {
        …
    }
    A a(100); // 对象 a 的SIZE 值为100
    A b(200); // 对象 b 的SIZE 值为200

    怎样才能建立在整个类中都恒定的常量呢?别指望const 数据成员了,应该用类中的枚举常量来实现。例如

    class A
    {
        …
        enum { SIZE1 = 100, SIZE2 = 200}; // 枚举常量
        int array1[SIZE1];
        int array2[SIZE2];
    };

    枚举常量不会占用对象的存储空间,它们在编译时被全部求值。枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点数(如PI=3.14159)。

  • 相关阅读:
    配置sonar、jenkins进行持续审查
    maven命令解释
    Maven中-DskipTests和-Dmaven.test.skip=true的区别
    maven之一:maven安装和eclipse集成
    Eclipse安装Maven插件
    IntelliJ IDEA单元测试和代码覆盖率图解
    关于Spring中的<context:annotation-config/>配置
    Java开发之@PostConstruct和@PreConstruct注解
    Java定时任务的三种实现方法
    JAVA之Mybatis基础入门二 -- 新增、更新、删除
  • 原文地址:https://www.cnblogs.com/houkai/p/3110599.html
Copyright © 2020-2023  润新知