上海大学软件工程研讨5_3
文件内容注释(File Contents) 每个文件都应该在其版权信息及作者信息后面 和内容前面有一个内容描述性的注释。 通常,头文件描述它所声明的类的目的及用法。 而源文件则应该包含更多有关实现和技巧性算 法的讨论信息。但如果你觉得这些信息对于头 文件的阅读者更有用,可以将其放在头文件中, 但在源文件中应该注明其文档在头文件中。不 要在头文件和源文件中重复注释,这样容易造 成歧义。
例子:
// 返回这个表的一个迭代器 // 当遍历结束时,由客户程序负责迭代器的释放 // 一旦此迭代器的创建者GargantuanTable对象被释放 // 客户程序不可再使用此迭代器 // // 迭代器被初始化为指向表的开始 // // 这个方法等价于: // Iterator *iter = table->NewIterator(); iter->seek(“”); return iter; // 如果你想立即寻找返回的迭代器中的另一个位置 ,使用 NewIterator()更快,而// 且避免了额外的查找。 Iterator* getIterator()const
如果你在文件开始就已对类进行了详细描述,可以在类 实现部分简单地声明“参见文件开始注释部分的完整描 述”,但注意,这里还是要添加少量注释。
函数注释(Function Comments)
函数声明部分的注释描述函数的用法,实现部分的注 释描述函数实现的操作。
每个函数声明的前面都应该有一个描述函数功能和用法 的注释。这些注释应该是描述性(Opens the file),而不 是祈使性的(Open the file),注释仅仅描述函数能够 完成什么功能而不是函数是怎么实现的,这些应该在函 数实现的注释中。 在函数声明注释中应该提到的信息类型: 1、输入和输出; 2、对于类成员函数,在该方法的调用周期外,对象是否 有引用参数,它是否会释放这些引用; 3、如果一个函数申请了内存,它必须释放它们; 4、参数是否可以是空; 5、函数的使用方法是否会影响其性能; 6、如果函数可重入。它是怎么实现同步的?
逻辑功能段进行注释
当给函数传入NULL、布尔值和整型值串时,应该 增加注释以说明这些值的意义,或者你可以使用常 量使代码自文档化。比较以下两段代码:
bool success = CalculateSomething(interesting_value, 10, false, NULL);// 这些参数都是 什么意思? VS bool success = CalculateSomething(interesting_value, 10, //默认基数 flase,//非第一次调用 NULL);//无回调
行注释(Line Comments) 同样,当行代码中有不明显的地方时,也需要在其行末 添加注释。这种行末注释应该以2个空白与代码分开。
// If we have enough money, mmap the data portion too. mmap_budget = max<int64>(0,mmap_budget – index_->length()); if(mmap_budget>=data_size && !mmapData(mmap_chunk_bytes,mlock)) return; // Error already logged.
K后跟混合大小写的名称:kDaysInAWeek。 所有编译时常量,不管是被声明为局部、 全局还是作为类的成员,都应该遵守与其 他变量命名有轻微差别的命名约定:k后跟 单词首字母大写的名称:
const int kDaysInAWeek = 7;
函数命名(Function Names)
正规函数名应该以大写字母开头,单词首字母大写,不使用下 划线。如果函数可能因错误而崩溃,应该在函数名后加上OrDie。 这仅适用于那些被产品代码调用或者正常操作有可能引起错误 的函数。
不要这么做: 不要试图描述代码本身。假设代码阅读者比你更了解 C++,既使这样,他/她也对你到底想做什么毫无头绪。
类注释(Class Comments)
每个类定义都应该伴随有说明其目的和用法的注释。
// 遍历GargantuanTable的内容。用法示例: // GargantuanTableIterator* iter = table->NewIterator(); // for(iter->seek(“foo”);!iter>done();iter->next()){ // process(iter->key(),iter->value(); // } // delete iter; Class GargantuanTableIterator能段进行注释的规范
文件注释(File Comments)
每个文件都应该提供版权信息,然后是文件内容的 综合性描述。 合法公告和作者信息行(Legal Notice and Author Line) 每个文件都应依次包括以下条目, 1、版权声明(比如Copyright 2008 Google Inc.); 2、一个许可引用。选择适合你项目使用的许可引用 (比如Apache 2.0、BSD、LGPL、GPL) 3、作者信息行说明文件原始作者 如果你对原始作者的文件做了实质性修改,可以在作者 信息行加上你的名字。当其他开发者有问题时,这样可 以方便他们正确地联系到修改者。
// Divide result by two, taking into account that x // contains the carry from the add for(int i = 0;i < result->size();i++){ x = (x <<8 )+(*result)[i]; (*result)[i] = x >> 1; X &= 1; }
然而,避免不必要的冗长注释且不要添加显而易见的注释。 比如下例外中,返回假的情况就没必要,因为这很明显:
// 如果表已被占满,不能再容纳实体,则返回真 bool IsTableFull();
当给构造和析构函数加注释时,注意,读者清楚地知道这些 函数的作用,所以诸如“销毁这个对象”的注释毫无意义。 注释内容应该说明构造函数怎样处理参数(比如它是否取得 指针的控制权)和析构函数怎么完成清理工作。如果这些不 很重要,可以省略它们。文件的开头注释中没有关于析构函 数的注释是很正常的。 函数定义注释(Function Definition) 每个函数都应该有一个注释来描述函数的功能和其完成这些 功能的实现技巧(如果有的话)。比如,你在函数定义注释 中,你可以描述编码中用到的技巧,给出大致的执行步骤或 者解释一下你选择这种实现而不使用其他替代方法的原因。 比如,你可能需要说明为什么函数前半部分需要锁而后半部 分不需要。 注意,不能简单地重复头文件或者其他地方函数声明部分的 注释。可以再次概括一下函数的功能,但焦点应该是函数是 怎么实现功能的。
AddTableEntry() DeleteUrl() OpenFileOrDie()
访问器和修改器(Accessors and Mutators) 访问器和修改器(get和set函数)应该与它们关联的变量名匹 配。下面显示了一个类的部分摘录,它有一个实例变量 num_entries class MyClass{ public: ... int num_entries() const{return num_entries;} void set_num_entries(int num_entries){num_entries = num_entries;} private: int num_entries_; }; 你也可以使用小写字母和下划线来命名非常短小的内联函数。 比如,如果一个函数的调用开销很小,在循环调用时,没必 要缓存其值,这时,小写字母命名是允许的。
类数据组成变量命名(Class Data Members) 数据成员(又叫实例变量或者成员变量)的命名与普通变量一样, 全部字母小写,可选的下划线分隔符,但应该以下划线结束。
string table_name_; string tablename_;
// 可以-以下划线结束 // 可以
结构体成员变量命名(Struct Variables) 结构体成员变量和普通变量命名规则一致,且不像类 成员变量以下划线结束。
变量注释(Variable Comments)
通常,一个变量的实际名称已经提供了足够和描述信息 来说明其用途。但某些情况下,可能需要更多注释。 类数据成员(Class Data Members) 每个类数据成员(也称实例变量或者成员变量)应该有一个 描述其用途的注释。如果这个变量能取得具有特殊意义的标 志值,比如NULL或-1,则需要加以说明。比如: Private: //记录表中实体的总数 //用于确保不打破数量限制。 //-1意味着表的实体数未知 int num_total_entries;
也可以使用替代方案,常量或自描述的变量:
const int kDefaultBaseValue = 10; const bool kFirstTimeCalling = false; callback *null_callback = NULL; bool success = CalculateSomething(interesting_value, kDefaultBaseValue, kFirstTimeCalling, null_callback);
可以看到,这里即有描述代码功能的注释,也有提醒 函数返回时错误已经被记录的注释。 如果有多行注释,将它们整齐排列将增加可读性。
DoSomething(); // Comment here so the comments line up DoSomethingElseThatIsLong(); // Comment here so there are two spaces // between the code and the comment {// One space before commnet when opening a new scope is allowed, // thus the comment lines up with the following comments and code DoSomethingElse(); // Two spaces before line comments normally }