开发管理之代码编码规范

发布时间 : 星期三 文章开发管理之代码编码规范更新完毕开始阅读

4.3.1.6.

4.3.1.7.

对于内置类型参数要传值

需要传指针不传引用的情形

a)内部需要用NULL状态(引用没有NULL状态) b)若参数是被new出来的,是将在函数内被释放

4.3.2. 返回值规则

4.3.2.1. 函数的输出值结果用输出参数(一般为指针)获得,状态用return返回

4.3.2.2. 如果返回一个对象,一般用引用传递,但有的情况下必须用值传递

例如:

class String {

? // 赋值函数 String & operate=(const String &other);

// 相加函数,如果没有friend修饰则只许有一个右侧参数

friend String operate+( const String &s1, const String &s2); private: char *m_data; } String的赋值函数operate = 的实现如下:

String & String::operate=(const String &other) { if (this == &other)

{

return *this; } delete m_data; m_data = new char[strlen(other.data)+1]; strcpy(m_data, other.data); return *this; // 返回的是 *this的引用,无需拷贝过程 }

对于赋值函数,应当用“引用传递”的方式返回String对象。如果用“值传递”的方式,虽然功能仍然正确,但由于return语句要把 *this拷贝到保存返回值的外部存储单元之中,增加了不必要的开销,降低了赋值函数的效率。例如:

String a,b,c; ?

a = b; // 如果用“值传递”,将产生一次 *this 拷贝 a = b = c; // 如果用“值传递”,将产生两次 *this 拷贝

String的相加函数operate + 的实现如下:

String operate+(const String &s1, const String &s2) { String temp; delete temp.data; // temp.data是仅含‘\\0’的字符串

temp.data = new char[strlen(s1.data) + strlen(s2.data) +1]; strcpy(temp.data, s1.data); strcat(temp.data, s2.data);

return temp; }

对于相加函数,应当用“值传递”的方式返回String对象。如果改用“引用传递”,那么函数返回值是一个指向局部对象temp的“引用”。由于temp在函数结束时被自动销毁,将导致返回的“引用”无效。例如: c = a + b;

此时 a + b 并不返回期望值,c什么也得不到,流下了隐患。

4.3.2.3. 尽量保持函数只有唯一出口

4.3.2.4. 若函数返回状态,尝试用枚举作类型

4.3.2.5. 当函数返回引用或指针时,用文字描述其有效性

4.3.2.6. 禁止成员函数返回成员的引用或指针

4.3.3. 函数内部规则

4.3.3.1. 在函数体的“入口处”,对参数的有效性进行检查,应正确使用断言(assert),

断言assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生的情况

例:

void *memcpy(void *pvTo, const void *pvFrom, size_t size)

{

assert((pvTo != NULL) && (pvFrom != NULL)); // 使用断言 byte *pbTo = (byte *) pvTo; // 防止改变pvTo的地址 byte *pbFrom = (byte *) pvFrom; // 防止改变pvFrom的地址 while(size -- > 0 )

*pbTo ++ = *pbFrom ++ ; return pvTo; }

4.3.3.2. 在函数的“出口处”,应对return语句的正确性和效率进行检查

4.3.3.3. return语句不可返回指向“找内存”(内部变量)的指针或引用,因为该内存在函

数体结束时被自动销毁

4.3.3.4. 要搞清楚返回的究竟是值、指针,还是引用

4.3.3.5. 如果函数返回值是一个对象,要考虑return语句的效率

4.3.4. 通用规则

4.3.4.1. 函数的功能要单一,不要设计多用途函数

4.3.4.2. 函数体规模要小,尽量控制在100行代码以内,不包括注释和空格行

4.3.4.3. 尽量避免函数带有记忆功能,相同的输入应当产生相同的输出(不用static变量)

示例:如下函数,其返回值(即功能)是不可预测的。

unsigned int integer_sum( unsigned int base )

{

unsigned int index;

static unsigned int sum = 0; // 注意,是static类型的。 // 若改为auto类型,则函数即变为可预测。 for (index = 1; index <= base; index++) {

sum += index; }

return sum; }

4.3.4.4. 用于出错处理的返回值一定要清楚

4.3.4.5. 引用的规则

a)引用被创建时同时被初始化

b)不能有NULL引用,引用必须与合法的存储单元关联 c)一旦引用被初始化,就不能改变引用的关系 d)引用的功能主要是传递参数和返回值

C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。 以下是“值传递”的示例程序。由于Func1函数体内的x是外部变量n的一份拷贝,改变x的值不会影响n, 所以n的值仍然是0。

void Func1(int x)

{

x = x + 10; } ?

int n = 0; Func1(n);

cout << “n = ” << n << endl; // n = 0

以下是“指针传递”的示例程序。由于Func2函数体内的x是指向外部变量n的指针,

改变该指针的内容将导致n的值改变,所以n的值成为10。

void Func2(int *x)

{

(* x) = (* x) + 10; } ?

int n = 0; Func2(&n);

cout << “n = ” << n << endl; // n = 10

以下是“引用传递”的示例程序。由于Func3函数体内的x是外部变量n的引用,x和n是同一个东西,改变x等于改变n,所以n的值成为10。

void Func3(int &x)

{

x = x + 10; } ?

int n = 0; Func3(n);

cout << “n = ” << n << endl; // n = 10

对比上述三个示例程序,会发现“引用传递”的性质象“指针传递”,而书写方式象“值传递”。实际上“引用”可以做的任何事情“指针”也都能够做,为什么还要“引用”这东西?

答案是“用适当的工具做恰如其分的工作”。

指针能够毫无约束地操作内存中的如何东西,尽管指针功能强大,但是非常危险。就象一把刀,它可以用来砍树、裁纸、修指甲、理发等等,谁敢这样用?

如果的确只需要借用一下某个对象的“别名”,那么就用“引用”,而不要用“指针”,以免发生意外。比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如果把取公章的钥匙交给他,那么他就获得了不该有的权利。

联系合同范文客服:xxxxx#qq.com(#替换为@)