【高质量代码】如何写出更高质量的C/C++代码(2):函数设计

函数是组成C/C++程序的基本元素,是将一段执行某项功能的代码进行了封装的代码段。为了实现设计的功能,函数的功能正确性是首要的前提,但是仅仅是正确还不够,其设计的科学性和合理性也是影响函数使用的重要因素。本文简要讨论C/C++函数设计和实现的一些基本规则。

1、引言:

每一个完整的C/C++函数都至少包含三个部分:返回值、函数名和参数。函数参数和返回值承担了调用者与被调用函数之间数据传递的功能,主要方式有三种:值传递、指针传递和引用传递,前两者为C标准,引用传递为C++标准。其中引用传递的性质类似于指针传递,但是使用方式类似值传递。

2、声明函数:

声明函数主要考虑函数的参数和返回值的问题。当然,函数名也是重要的一部分,在设计函数名时,应当注意函数名体现函数的功能,且不产生歧义。通常使用一句英文表示的一个动作或特性来作为函数名,单词之间通过大小写转换来区分。

2.1、函数的参数:

函数的参数应当书写完整,不应只写类型而省略参数名称。当函数没有参数时,使用void作为参数。

void Function1(int , int);//不良风格
void Function2(int nParam1, int nParam2);//良好风格
void Funciton3();//不良风格
void Function4(void);//良好风格

参数名称要科学命名,应反映传递给该参数的实际意义,不要简单使用a、b等简单的命名。如一个计算矩形面积的函数,可以声明成如下形式:

int GetRectArea(int a, int b);//不良风格
int GetRectArea(int nWidth, int nHeight);//良好风格

如果函数包括输入参数和输出参数,一般输出参数(即目的参数)放在前面,输入参数(即源参数)放在后面。如字符串拷贝函数:

void StringCopy(char *strDst, char *strSrc);
char str[20];
StringCopy(str, “Hello World”);

有些仅仅作为输入数据,在函数内部不能修改的参数指针,可以声明为const类型进行保护,这样一旦函数体内视图修改该参数,则会产生错误。如果传值参数仅作为输入参数,则可声明为const &类型,省去临时对象的构造和析构过程,提高效率。如上面GetRectArea函数的参数都可以声明为const &类型,StringCopy函数的strDst参数可以声明为const类型:

void GetRectArea(const int &nParam1, const int &nParam2);
void StringCopy(const char *strDst, char  *strSrc);

2.2、函数的返回值

一些简单的函数,由于几乎不可能出现错误,且一般只有一个计算结果,那么可以将计算结果通过返回值传递给调用者。对于复杂函数,返回值通常用于返回错误标识,而计算结果通过输出参数获得。如果需要返回多个参数,除了定义多个输出参数外,还可以定义一个输出结构体,在输出之前将输出值封装在一个结构体对象中整体返回。

函数返回值的类型有“返回值”和“返回引用”两种设计。其区别是,“返回值”会产生一个临时变量作为函数返回值的副本,而“返回引用”时不会产生值的副本。有些时候选择“返回引用”可以提高效率,而有些时候必须“返回值”否则可能出错。

首先需要注意到一个问题就是,绝对不要返回局部对象的引用,因为局部对象在函数调用结束之后就会被释放,引用指向的对象会是一片未知区域。比如以下代码是不允许出现的:

int& GetRectArea(const int &nWidth, const int &nHeight)
{
	int area = nWidth * nHeight;
	return area;
}

在类的实现函数中,如果该函数返回的是该对象自身,那么可以通过this指针返回该对象的引用。典型的例子如string的赋值函数:

String& String::operator =(const String &str)
{
	if (this == &str)
	{
		return *this;
	}
	delete [] m_string;
	int len = strlen(str.m_string);
	m_string = new char[len+1];
	strcpy(m_string,str.m_string);
	return *this;
}

在通过返回this指针的对象到引用时,不会把本地对象拷贝到上层函数的对象内存,而是直接返回当前对象本身,降低了不必要的开销,提高了效率。

3、函数的实现

函数的实现方法千差万别,然而在函数体的一开始以及返回时可以对参数和返回值进行检查以防止不必要的错误发生。

3.1、在函数入口处,检查参数的有效性。

可以使用assert防止非法参数,这样可以预防许多程序的错误。assert是仅在debug模式下生效的宏定义,用于检查不应该发生的情况。如以下函数中,采用assert防止输入参数为空:

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;
}

3.2、在函数返回之前,检查返回值的正确性和效率。

需要注意的事项有:

  1. 不可以返回指向栈对象的指针或者引用,因为栈对象在返回时将被销毁;
  2. 返回值的类型(值/指针/引用)应与函数声明一致;
  3. 考虑返回对象的效率;

对于提高返回对象的效率而言,临时对象是否在栈中创建和销毁是不同的。如以下代码:

String temp(s1 + s2);
return temp;

此时,程序的流程如下:

  1. 创建temp对象,调用拷贝构造函数初始化;
  2. 调用拷贝构造函数将temp复制到外部存储单元;
  3. 函数结构,调用析构函数销毁temp对象。

而使用以下方式:

return String(s1 + s2);

此时,临时对象将直接创建在外部存储单元中,不再调用拷贝构造函数和析构函数,效率更高。

时间: 2024-10-27 22:44:18

【高质量代码】如何写出更高质量的C/C++代码(2):函数设计的相关文章

【高质量代码】如何写出更高质量的C/C++代码(1):内存管理

内存的管理是C/C++开发程序过程中的一个比较麻烦的问题.对于经验不是足够丰富的程序员来说,开发比较复杂的程序的时候几乎肯定会遇到内存管理方面的bug.对C/C++语言以及编译机制深入的理解和养成良好的编程习惯可以尽量减少这类bug产生的几率. 1.C/C++程序运行时内存结构简介 一个典型的C/C++编译的进程所占用的内存空间通常分为5个部分,由低地址到高地址分别为: 代码段(Code/Text Segment):保存可执行程序运行的二进制代码段. 数据段(Data Segment):保存进程

大数据可以创造出更高质量的价值

作为最早洞见大数据时代发展趋势的数据科学家之一,舍恩伯格在数博会"数据资产化发展论坛"上发表了<大数据的大价值>主题演讲.舍恩伯格认为,大数据是可以反复使用的资源,人们可以利用大数据创造出更高质量的价值. 舍恩伯格说,如今,数据已经成为了有价值的公司资产.重要的经济投入和新兴商业模式的基石.虽然数据还没有被列入企业的资产负债表,但这只是一个时间问题.人们必须意识到数据价值,并合理加以利用. 什么样的数据可与未来潜在因素发生更加紧密的联系?舍恩伯格认为,关键就在于让数据&qu

【译】使用 currentColor 属性写出更好的 CSS 代码

本文讲的是[译]使用 currentColor 属性写出更好的 CSS 代码, 总有一些极其强大的 CSS 属性在目前已经有了很好的浏览器支持,但却很少被开发者使用. currentColor 就是这样的属性之一. MDN 把 currentColor 定义为: currentColor 代表了当前元素被应用上的 color 颜色值.它允许让继承自属性或子元素属性的 color 属性为默认值而不再继承. 在本文中,我们将通过一些有趣的方式来概述如何使用 CSS currentColor 这一关键

掌握解决问题的艺术,学会迭代开发,成为协作开发的专家,然后为写出更好的代码而担忧(转)

很多开发人员普遍犯有一个错误,认为他们的工作就是写代码.这不是一个开发人员要做的事情. 一个开发人员的工作是解决问题. 解决问题的一部分过程通常涉及到写代码,但是这部分工作是非常非常小的.开发有用的东西才花更多时间. 明白如何迭代开发,随着对问题有更好的理解,你才能给难题增加一些小功能,因为从头开发完美的产品是不可能的.不用写代码就能验证功能,因为很明显,写代码是相当昂贵的. 用于测试.评测和抛弃想法的系统也是极其重要的,因为要是没有它,整个开发组将耗费越来越多的精力,还有用来帮助他们执行得更有

[译] SQL 指引:如何写出更好的查询

本文讲的是[译] SQL 指引:如何写出更好的查询, 原文地址:SQL Tutorial: How To Write Better Queries 原文作者:Karlijn Willems 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:临书 校对者:steinliber, xiaoyusilen SQL 指引:如何写出更好的查询 结构化查询语言(SQL)是数据科学行业的一种不可或缺的技能,一般来说,学习这项技能是相当简单的.然而大多数人都忘记 SQL

写出更轻巧、更快并且更不会让你头疼的CSS

网页制作Webjx文章简介:写出更轻巧.更快并且更不会让你头疼的CSS. 为什么我们的CSS变得一团糟--我们真的很容易陷入这样的困惑中. 有时这是一开始就马虎编程的结果,有时是由于后期多重的附加代码(hacks)和修改造成的. 无论是哪种原因,这都不是无法避免的.写出干净,超级可管理的CSS很简单,只要你走对了路,你的代码会更便于今后的维护和编辑. 写出更轻巧.更快并且更不会让你头疼的CSS,以下这10个技巧将会提高你这方面的能力. 1.保持条理性 像任何事情一样,让自己保持条理性(有组织)是

c#中double型的输出代码怎么写通用性更强?

问题描述 c#中double型的输出代码怎么写通用性更强? c#中double型的输出代码怎么写通用性更强?就是可以在控制台输出同样的代码也可以在其他窗体输出么? 解决方案 将输出代码包装成委托: 假设这是你之前的代码 void foo() { double d = 123.456; Console.WriteLine(d); } 为了通用,你需要把输出的部分抽取出来,变成 void foo(Action<double> output) { double d = 123.456; output

吸烟如何妨碍你写出更好的程序

问题描述 程序员工作压力大,工作时间长,很多人都有吸烟的习惯.本来我们对吸烟危害的认识只在于伤肺,有些人会说,"我不在乎,我的观念是livefast and dieyoung",但是当吸烟还伤脑,这下问题就严重了.你不但死得快,有生之年创造出的产品也不怎么样,没有人会记住你年轻.短暂又毫无闪光点的生命.这次环环就带大家来看看吸烟会怎么妨碍你写出更好的程序.一项新研究发现,抽烟不仅会伤害你的肺部,还有可能影响你的大脑.之前有研究表明,相比非吸烟人群,早年开始吸烟的人到了晚年后,记忆力和认

谷歌面试题:给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数

给定能随机生成整数1到5的函数,写出能随机生成整数1到7的函数. 我的想法: 编写一个生成0和1的随机函数:  step1. 调用给定的随机函数original_rand()生成一个数  如果==3 goto step1  如果<3 return 0  如果>3 return 1  编写一个生成1到7的随机函数  调用生成0和1的随机函数3次,构成000或001或010.......  如果???不等于0返回,否则重新生成. int rand_01() { int r = original_r