1、 函数设计的技巧
函数是由函数参数、返回值和函数体3个要素组成的。
1.1函数体设计的规则
·函数的功能要单一,不要设计多用途的函数
·函数体的规模要小,尽量控制在50行代码以内
·尽量避免函数带有“记忆”功能。相同的输入应当产生相同的输出。带有“记忆”功能的函数,其行为可能是不可预测的,因为它的行为可能取决于某种“记忆状态”
·要检查输入参数的有效性,还要检查通过其他途径进入函数体内的变量的有效性,例如全局变量、文件句柄等
·用于出错处理的返回值一定要清楚,让使用者不容易忽视或误解错误情况
·使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。
·在函数的入口处,使用断言检查参数的有效性(合法性)。
1.2参数的设计规则
·参数的书写要完整
void SetValue(int width, int height);//良好的风格
void SetValue(int,int);//不良的风格
·如果参数是指针,且仅作为输入用,则应在类型前加const,以防止它在函数体内被修改。
void StringCopy(char *strDestination, const char *strSource);
·如果输入参数以值传递的方式传递对象,则宜改用“const &”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。传递引用实际上也会产生临时的指针传递,只是在对象的拷贝需要消耗很多时间的时候,才会考虑传递引用。
·参数的个数应该控制在5个以内,不宜太多。
·尽量不要使用参数和类型不确定的参数,这种风格的函数在编译时丧失了严格的类型安全检查
1.3返回值的设计规则
·不要省略返回值的类型,如果没有返回值,设置为返回void类型。
·不要将正常值和错误标志混在一起返回。正常值用输出参数获得,而错误标志用return语句返回
2、 宏定义的使用技巧
宏定义了一个代表特定内容的标识符。预处理程序会把源代码中出现的宏标识符替换成宏定义时指定的值
2.1防止头文件不被重复包含
#ifndefine _INCLUDER_HEADER_H_
#define _INCLUDER_HEADER_H_
#include *public.h
#endif
该段代码的作用防止了public.h被工程重复包含
2.2定义代表某个值的全局符号
比如,用预处理指令#define声明一个常数,用以表明一年中有多少秒
#define SECONDS_PER_YEAR (60*60*24*365)UL //定义带参数的宏
写一个宏,这个宏输入两个参数并返回较小的一个:
#define MIN(A,B) ((A)<=(B)?(A):(B))
2.3_DEBUG宏的运用技巧
_DEBUG是编译器留给我们的预编译属性。如VC编译器,对于每个工程都有Debug和Release两种不同的模式。在Debug模型下面,_DEBUG会被编译器自动定义,在Release模式下则不会。因此我们可以使一段程序产生不同的输出,如:
…
#ifdef _DEBUG
cout<<”debug”<<endl;
#else
cout<<”release”<endl;
#endif
…
这在大型工程中是十分有用的,比如有一个程序要求用户交互输入50个数据,然后根据输入计算出结果。如果调试时每次手动输入50个数据是很辛苦的,也是容易出错的,所以我们可以在调试的时候把数据指定好,而发行的时候显示交互窗口,这样做既不改变程序结构,又方便调试。
#ifdef _DEBUG
for(i=0;i<50;i++)
A[i]=i
#else
ShowInputWindow(A);
#endif
3、 const使用技巧
const是constant的缩写,“恒定不变”的意思。被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。鉴于其有这么多优点,const关键字最常用的是用来定义常量。const更大的魅力是它可以修饰函数的参数、返回值和函数的定义体。
3.1 const常量的定义
常量是一种标识符,它的值在运行期间恒定不变,在上一节中,阐述#define定义的常量,称为宏常量。那么利用const定义的常量称为const常量。合理地利用常量可以提高程序的可读性、易修改性等。
3.2 const常量的定义技巧
·尽量用含义直观的常量来表示那些将在程序中多次出现的数字或字符串
const int MAX=100;//C++语言的const常量
const float PI=3.1415926
·需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义文件的头部。为便于管理,可以把不同模块的常量集中存放在一个公共的头文件中。
·如果某一常量与其他常量密切相关,应在定义中包含这种关系,而不应给出一些孤立的值。
const float RADIUS=100;
const float DIAMETER=RADIUS*2;
3.3 const在函数中的使用
3.3.1 const修饰函数参数
·被const修饰的输入参数,在函数中不能修改它的值,防止意外的变动发生,能加强函数的健壮性。
·作为返回值使用,说明函数的返回值是不能被修改的。在取得返回值时应用const int a=func()
·const修饰类成员函数体
const修饰的函数体称为常函数,说明函数是不能修改类中成员的值的,不过只能用于修饰类的成员函数中。
3.3.2 实例代码
/**//**//**//**********************************/
/**//**//**//*说明:演示const在函数中的作用
/*const:修饰参数
/*const:修饰返回值
/*const:修饰函数体
/**********************************/
#include<iostream.h>
#include<assert.h>
//const输入修饰输入参数,在函数中不能修改它的值,防止意外的变动发生,能加强函数的健壮性
char* StringCopy(char *strDestination,const char *strSource)
{
assert((strDestination!=NULL)&&(strSource!=NULL));
char* address=strDestination;
while((*strDestination++=*strSource++)!='\0')
NULL;
return address;
}
//const修饰返回值
const char *GetString(void)
{
char* szOut="日期输出结束";
return szOut;
}
//类DTime
class DTime
{
//操作
public:
DTime(int iYear,int iMonth,int iDay)
{
m_nYear=iYear;
m_nMonth=iMonth;
m_nDay=iDay;
}
int GetYear() const{return m_nYear;}//const修饰函数体
int GetMonth() const{return m_nMonth;}
int GetDay() const{return m_nDay;}
public:
int m_nYear;
int m_nMonth;
int m_nDay;
};
int main()
{
char szOutStr[256];
char* szInStr="输入年月日";
StringCopy(szOutStr,szInStr);
cout<<szOutStr<<endl;
int nYear;
int nMonth;
int nDay;
cin>>nYear;
cin>>nMonth;
cin>>nDay;
DTime dt(nYear,nMonth,nDay);
cout<<dt.GetYear()<<"-"<<dt.GetMonth()<<"-"<<dt.GetDay()<<endl;
const char* str=GetString();
cout<<str<<endl;
return 0;
}
3.4 const指针
const指针有两种格式,一种是指针常量,表示指针本身是常量,指针值不可修改,指向的内容可以修改;另外一种是指向常量的指针,表示指向的对象是常量,指针值可以修改。
① 指针常量,指针本身是常量,参考代码如下:
char ch[5]="lisi";
char* const pStr=ch;
pStr="zhangsan";//错误
*pStr='W';//正确
② 指向常量的指针,指针值可以修改,指向内容不可改变,参考代码如下:
char ch[5]="lisi";
char const *pStr=ch;
pStr="wangwu";//正确
*pStr='w'//错误
3.5 类const成员变量的初始化
const修饰的成员变量,必须进行初始化,且不能更新。类中声明const成员变量,只能通过初始化列表的方式生成构造函数对成员变量进行初始化。
(代码有问题,修改ing)
程序的运行结果为:
100:10:100
0:10:0
在程序中,声明了如下3个常数据成员。
·const int &r;
·const int a;
·static const int b;
其中,r是常int型引用,a是常int型变量,b是静态常int型变量。程序中对静态数据成员b进行初始化。
构造函数的格式如下所示:
Ext(int i):a(i),r(a)
{
}
其中,冒号后面是一个数据成员初始化列表,它包含两个初始化项,用逗号进行了分隔,因为数据成员a和r都是常类型的,需要采用初始化格式。
3.6 const与宏常量的区别
1.const常量有数据类型,而宏常量没有数据类型
编译器可以对前者进行类型安全检查,而对后者只能进行字符替换,没有安全检查,并且在字符替换时可能会产生意料不到的错误。
2.编译器对二者的调试
有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++程序中只使用const常量而不适用宏常量,即const常量完全取代宏常量。
4、 sizeof使用技巧
4.1、sizeof运算符的特点
sizeof是一个单目的操作符,用于计算操作数的存储大小,不过它更像是一个特殊的宏,因为它在编译阶段就已经求值了。比如
#include <iostream.h>
void main()
{
int a=0;
cout<<sizeof(a=3)<<endl;
cout<<a<<endl;
}
输出结果为4、0而不是4、3,就在于sizeof在编译阶段处理的特性,由于sizeof不能变编译成机器码,所以在sizeof作用范围内,也就是()里面的内容也不能被编译,而是被替换成类型。=操作符返回左操作数的类型,所以a=3相当于int,而代码页被替换为:
int a=0;
cout<<4<<endl;
cout<<a<<endl;
4.2、sizeof的应用技巧
1)用于数据类型
利用sizeof运算符计算该类型占用的字节数,sizeof的使用形式为sizeof(type),数据类型必须用括号括住。
2)用于普通数据类型的变量
sizeof使用形式:sizeof(var_name)或sizeof var_name,变量名可以不用括号括住。如sizeof(var_name)、sizeof var_name等都是正确形式。带括号的用法更普遍,大多数程序员采用这种形式。
3)用于指针
当操作数是指针时,sizeof依赖于编译器。例如在Microsoft C/C++6.0中,near类指针字节数为2,far、huge类指针字节数为4.(near类,far、huge类是什么?)
4)用于数组
当操作数具有数组类型时,其结果是数组的总字节数。
#include<iostream.h>
void main()
{
char ss[100]="0123456789";
int nn[100]={0};
int nSS=sizeof(ss);
int nSSFirst=sizeof(*ss);
int nNN=sizeof(nn);
cout<<"nSS="<<nSS<<endl;
cout<<"nSSFirst="<<nSSFirst<<endl;
cout<<"nNN="<<nNN<<endl;
}
在VC++6.0的输出结果
nSS=100
nSSFirst=1
nNN=400
5)用于结构体
在默认情况下,为了方便对结构体内的元素访问和管理,当结构体内的长度都小于处理器位数的时候,便以结构体中最长的数据元素为对齐单位,也就是说结构体的长度大于最长的数据元素的整数倍。如果结构体内存长度大于处理器的位数,那么就以处理器的位数为对齐单位。但是结构体内类型相同的连续元素将在连续的空间内和数组一样
详细解释可看:http://hi.csdn.net/link.php?url=http://topic.csdn.net%2Fu%2F20100125%2F18%2F71fdb3a4-36a4-4c0f-a7ea-b9dcd13ef6ec.html
#include<iostream.h>
struct A
{
char ch;
int n;
};
void main()
{
int n=sizeof(A);
cout<<"sizeof(A)="<<n<<endl;
cout<<sizeof(char)<<endl;
cout<<sizeof(int)<<endl;
}
6)用于类
sizeof运算符对于类的用法和对结构体的用法是一致的。
#include<iostream.h>
class A
{
char ch;
int a;
int b;
};
class B
{
};
class C
{
static int sVale;
};
void main()
{
int n=sizeof(A);
int m=sizeof(B);
int k=sizeof(C);
cout<<"sizeof(A)="<<n<<endl;
cout<<"sizeof(B)="<<m<<endl;
cout<<"sizeof(C)="<<k<<endl;
}
其中,class A中实际变量占用了9字节,因为类的长度一定是最长的数据元素的整数倍,所以结果为12。对于编译器我而言,即便类是空的,编译器也会给出一个空间,所以sizeo(B)=1;因为静态变量时存放在全局数据区里面的,而sizeof只计算栈中分配的大小,所以sizeof(C)=1。
4.3、sizeof与srtlen()的区别
1、二者的区别
sizeof是操作符,strlen是函数。
sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以“\0”结尾的
2、实例代码
#include<iostream.h>
#include<string.h>
void main()
{
char* str=new char[100];
cout<<"sizeof(str)="<<sizeof(str)<<endl;
cout<<"strlen(str)="<<strlen(str)<<endl;
char s;
cout<<"sizeof(s)="<<sizeof(s)<<endl;
cout<<"strlen(&s)="<<strlen(&s)<<endl;
}
说明:strlen返回的是实际串长,而sizeof返回的是变量占用的空间
例 如
memset(str, 0, sizeof(str));//用strlen和sizeof()有什么区别
用sizeof的话,只给str所指向的内存块连续4个字节清0
用strlen的话,只给str所指向的字符串全部清0
sizeof(str)返回这个指针变量所占的内存字节数目
strlen(str)返回str所指向的字符串的长度
如果还想获得更多关于《Visual C++代码参考与技巧大全》的内容,可点击下面网址,http://www.cppblog.com/kangnixi/archive/2010/01/13/105591.html