最近公司对编码风格进行总结,也学到了不少东西。
Windows代码
如果你一直在windows平台下编码,这儿有必要强调一下下面的规则:
1) 不要使用匈牙利命名法,正如你没有必要将循环控制变量i写成iI或者iLoopControl一样,而且很显然的,匈牙利命名法完全不适用C++模版,任何试图通过变量前缀来区分map<string, string>和map<string, int>的想法都是很折磨人的;
感觉完全遵守匈牙利命名法很累人的(想想VC里面可怕的变量名,苍天呀),尤其是临时的函数内的局部变量。但是如果类的成员,用m_iXX,m_strXXX来修饰下视觉上还是比较美观的。尤其是对于全局变量用g_XXX也很清晰。
2) Windows系统定义了很多原有内建类型的同义词,如DWORD
、HANDLE
等等,在调用Windows API时这是完全可以接受甚至鼓励的,但在其它情况下还是尽量使用原来的C++类型,例如,使用const TCHAR *
而不是LPCTSTR
;
更喜欢用简单的名称LPCTSTR明显比const TCHAR *写起来方便,但是移植可能很不方便。
3) 不要使用#pragma once
;放在头文件里面作为包含保护,使用C和C++标准的包含保护(注:#ifndef ...);
从来没有用过#pragma once - -
4) 除非万不得已,否则不使用任何不标准的扩展,如#pragma
和__declspec
,允许使用__declspec(dllimport)
和__declspec(dllexport)
,但必须通过DLLIMPORT
和DLLEXPORT
等宏定义,以便其他人在共享使用这些代码时容易放弃这些扩展。
都是微软VC自动生存DLL工程的,接口都写在def文件里了,这些基本没有用过 - -
头文件:
通常,每一个.c(C的源文件)和.cpp文件(C++的源文件)都有一个对应的.h文件(头文件),也有一些例外,如单元测试代码和只包含main()的体积较小的源文件。
正确使用头文件可令代码在可读性、文件大小和性能上大为改观。
一个.cpp对于一个.h,我一般一个类写在一对hpp文件里面,但有时候某个类的成员特别大,功能特别多,就分成多个.cpp和1个.h。在Source Insight里面看起来比较舒服,也不会把.cpp文件变的特别长。
避免头文件被重复包含
所有头文件都应该使用#define防止头文件被重复包含,为保证唯一性,头文件的命名应基于其所在项目源代码树的全路径。例如,项目
foo
中的头文件
foo/src/bar/baz.h
按如下方式保护:
#ifndef __FOO_BAR_BAZ_H__
#define __FOO_BAR_BAZ_H__
...
#endif // __FOO_BAR_BAZ_H__
没什么意见,不是很喜欢使用路径,更喜欢使用该文件的作用来作为宏定义。
============================================================
好乱,感觉不会写了,还是写写以前不知道或者没注意的东西吧。
=====================================================================
/*b.h*/
class b
{
a _a;
};
/*a.h*/
class a
{
}
---------
那么b.h可以编译过去吗?(b.h里没有include "a.h")
如果又其他一个文件调用b时,同时include "a.h",include "b.h",那么就一切OK,头文件的读取是次序的,所以顺利编译通过。
---------------------------------------------------------------------
命名空间:
是用using name std好,还是每个都用上std::前缀好呢?std::string,std::list
公司里问一圈,除了喜欢用boost的,都很懒很懒的时候用第一种。
当然,我也是懒人之一,呵呵。
---------------------------------------------------------------------
static加变量是什么意思(学过C的都知道吧,毕竟任何一本书都会提到)
static加类成员是变成全局函数。
那么static加非成员函数有什么用?
函数默认都是全局的,加上static那么,就变成只有本文件才能使用了。
---------------------------------------------------------------------
class类型全局变量,如果有多个,而构造函数依赖另外一个,那么可能会有问题。
因为这种变量,先构造哪一个是不能控制的。
就算只有一个如果用了STD的string,list也有问题,因为你无法确认他们的创建没有关系。
我写代码的时候,一般就起一个class类型的全局变量来放置配置信息,成员变量都用基本类型,用全局指针,总是感觉不放心。
---------------------------------------------------------------------
构造函数中,直接return;不会造成创建失败,也就是new仍然返回值。
目前而言,没有办法让new返回NULL。
而且我们老大说了个我一直不知道的事情,现在C++ new失败是抛异常!而不是返回空!
另外2位大佬献身说明,捕获了异常也没用,程序肯定崩溃,因为new失败,不是说明没有内存了(因为可以写磁盘),而是没有地址空间了!捕获了异常也是程序崩溃。说明程序有问题!
所以也就说,从此我们写代码不用判断new失败的情况了,耶!不用if(NULL=XX)或者if(!XX)
---------------------------------------------------------------------
就算没有写无参数的构造函数,系统也没有给你生成一个。
也就是说,你们没有无参数的构造函数,但是你new C()依然成功。当然内部处理肯定出错了。
---------------------------------------------------------------------
显式的构造函数:
Foo::Foo(string name)//构造函数
那么某个函数以这个类为参数 foo2(Foo),你直接将string变量传递进去,一样OK!自动帮你生存Foo的实例。
---------------------------------------------------------------------
struct没有成员函数,但可以用指向函数的指针实现。
比如: struct test{ int a; int (*add)();//当函数指针指向不同的函数可以实现对不同的操作 }; int addd(int a) { return ++a; } main() { int i; struct test t; t.a=1; t.add=addd; printf("%d\n",i=t.add(t.a)); return 0; }---------------------------------------------------------------------
友元用来做单元测试比较好
---------------------------------------------------------------------
windows里面的流竟然不支持64位×××,还是老老实实用printf吧。
---------------------------------------------------------------------
对迭代器和模板类型来说,要使用++i,而不要用i++。
因为i++需要对原来的表达式的值进行一次拷贝,当然如果是基本类型当然无所谓
随便提一下,在for循环里便利map,erase掉自己需要的,最好不要把i++写到for括号里。
for(i!=map.end;)
{
if(...)
map.erase(i++);
else
++i;
}
---------------------------------------------------------------------
对于常数还是define宏定义的好,因为可以写头文件里随便用,但是const定义的常量只能给被文件用,用extern也没用,取不到值。
---------------------------------------------------------------------
---------------------------------------------------------------------