微软Office的源代码样式规范 —— 绝对机密文档!!!

该文档为Office开发中的C和C++源码提供风格指南,列出使用和避免的C++特性及理由,涵盖类、其他C++特性、常见C/C++问题、格式约定等内容,还对虚拟函数、构造函数、析构函数等使用给出建议,以实现简单、清晰、高效等目标。
摘要由CSDN通过智能技术生成

Office Source Code Style Guide
Dave Parker, 6/30/95

Abstract
This document outlines a general style guide for C and C++ source code in Office Development.  The main purpose here is to list features of C++ which we will use and which we will avoid, along with the basic rationale for doing so.  There are also standards for basic coding issues for the sake of consistency within the code and robust constructs.  This is not a complete list of C/C++ language features with commentary.  Rather, it mentions only the issues we consider important.  Knowledge of C++ is assumed.
Contents
1. GENERAL GOALS 3
2. CLASSES 3
2.1 CLASS VS. STRUCT 4
2.2 PUBLIC, PRIVATE, AND PROTECTED MEMBERS 4
2.3 DATA MEMBERS 4
2.4 VIRTUAL FUNCTIONS 5
2.5 CONSTRUCTORS 5
2.6 DESTRUCTORS 6
2.7 NEW AND DELETE 7
2.8 OPERATORS 7
2.9 INHERITANCE 8
2.9.1 Inheritance of Interface vs. Implementation 8
2.9.2 Inheritance vs. Containment 10
2.9.3 Multiple Inheritance 11
3. OTHER C++ FEATURES 11
3.1 CONSTANTS AND ENUMERATIONS 12
3.2 REFERENCES 12
3.3 CONST PARAMETERS AND FUNCTIONS 13
3.4 DEFAULT ARGUMENTS 13
3.5 FUNCTION OVERLOADING 14
3.6 OPERATOR OVERLOADING 14
4. COMMON C/C++ ISSUES 14
4.1 #IFDEFS 14
4.2 GLOBAL VARIABLES 15
4.3 MACROS AND INLINE FUNCTIONS 16
4.4 OPTIMIZATION 16
4.5 WARNINGS 17
4.6 PRIVATE DATA AND FUNCTIONS 17
4.7 TYPEDEFS 17
4.8 BASIC DATA TYPES 17
4.9 POINTERS 18
4.10 SWITCH STATEMENTS 19
4.11 ASSERTS 19
4.12 ERRORS AND EXCEPTIONS 19
5. FORMATTING CONVENTIONS 20
5.1 NAMING CONVENTIONS 20
5.2 FUNCTION PROTOTYPES 21
5.3 VARIABLE DECLARATIONS 22
5.4 CLASS DECLARATIONS 22
5.5 COMMENTS 23
5.5.1 File Headers and Section Separators 23
5.5.2 Function Headers 24
5.5.3 In-Code Comments 25
5.5.4 Attention Markers 25
5.6 MISC. FORMATTING CONVENTIONS 26
5.7 SOURCE FILE ORGANIZATION 27
5.7.1 Public Interface Files 27
5.7.2 Private Interface Files 28
5.7.3 Implementation Files 28
5.7.4 Base Filenames 29
6. INTERFACES TO DLLS 29
6.1 C FUNCTIONS AND GLOBAL VARIABLES 29
6.2 COMMON C/C++ PUBLIC HEADER FILES 29
6.3 LIGHTWEIGHT COM OBJECTS AND ISIMPLEUNKNOWN 30
7. APPENDIX A: BASIC HUNGARIAN REFERENCE 33
7.1 MAKING HUNGARIAN NAMES 33
7.2 STANDARD BASE TAGS 33
7.3 STANDARD PREFIXES 34
7.4 STANDARD QUALIFIERS 35

 1. General Goals
C++ is a complex language that provides many ways to do things, and going 搘hole hog” on all of its features can lead to confusion, inefficiency, or maintenance problems.  All Office developers need to become experts on the features we will use, and avoid the others in order to form solid conventions within the group that we are all comfortable with.  Our use of C++ features will be fairly conservative.  We抎 much rather err on the side of just dealing with C, which we抮e all used to, then screwing up our app with a new concept that not all of us are used to.
Underlying the choice of all of the style decisions are a few basic goals, as listed below.  When in doubt about a particular issue, always think about the spirit of these goals.  Sometimes these goals will conflict, of course, and in these cases we try to either prioritize the tradeoffs or use experience (either our own or from other groups that have used C++ extensively).
1. Simplicity.  When in doubt, keep it simple.  Bugs are related mostly to complexity, not code.
2. Clarity.  The code should do what it looks like it抯 doing.  Other people need to be able to understand your code.
3. Efficiency.  Speed and size are important.  Using C++ does not imply big and slow.  There are plenty of perfectly reasonable ways to make things as fast or faster than the normal C way.  Speed and size often trade off, and most people probably err on the side of choosing speed too often.  Remember that 20% of the code is responsible for 80% of the time.  In most cases, we抮e more concerned about fitting comfortably in less RAM.
4. Appropriateness.  Use the language construct that is appropriate for the abstraction or operation you are trying to do.  Do not abuse the language.  Don抰 use a construct just because it happens to work.  Definitely don抰 use a strange construct to amaze and confuse your friends to try to show how smart you are.
5. Natural transition from C to C++.  We all used to be C programmers.  Others that look at our code are still C programmers (e.g. Word and Excel).  When possible, avoid C++ constructs where a C programmer抯 instinct causes a wrong assumption.
6. Catch Errors Early.  Having the compiler catch an error is ideal.  Having debug code (e.g. Asserts) catch it is the next best thing, etc.  Declare things in such as way as to give the compiler the best chance at catching errors.
7. Fast builds.  Total generality and modularity can cause lots of inter-dependencies between files, which can have a dramatic impact on build times.  This is a constant time sink for everyone.  It is often worth rearranging things a little to make incremental builds faster.
8. Consistency.  The whole point of having a style guide is that programmers are never totally autonomous, even when the group has strong code ownership.  Other people need to read and understand your code.  Everyone has to give a little to have a consistent style guide, but everyone gains it back when they read or debug other people抯 code.
2. Classes
C++ classes are a nice way to encapsulate code and data into a single unit, which provides a good paradigm for object-oriented implementations as well other features such as flexible access control, convenient and type-safe polymorphism, and the possibility of code reuse via inheritance.
At the most general, classes are an extension to the built-in typing of C which allows you to define your own types along with the operations on that type.  Taken to the extreme, every piece of data in a program could be an instance of a class.  However, we will not go nearly this far in Office.  We will use classes when there is a good reason to, such as the concept being implemented is inherently object-oriented or polymorphism is required.  It has been the experience of many people that programs that use classes for everything evolve into systems that are complex and inefficient.  Although this may not be the fault of any particular class, complex class hierarchies can lead to needless complexity, and overly abstracted concepts can easily lead to inefficiency.
In general, we will avoid allocating classes on the stack and passing classes by value, because this is where the use of constructors and destructors gets you into the most trouble.  Most classes should be allocated via new, freed by delete, and passed by pointer.  In addition, we will never declare a global variable which is an instance of a class that has a constructor, because this causes a bunch of C runtime stuff to get linked in and stuff to happen at boot time to construct the thing, which is a big performance hit.  Using only heap-allocated classes implies we抣l probably use classes only for relatively complex objects that you would normally have in the heap anyway, not simple things like basic data types.  Beyond this, it is a judgment call when to use a class.  Use one if there is a good reason, but not if a more straightforward solution is just as good.
Summary:
 Use classes to encapsulate the implementation of an object-oriented concept.
 Use classes to implement polymorphism.
 Avoid allocating class instances on the stack and passing them by value.  Use new and delete, and pass them by pointer.  This implies not using classes for simple data types.
 Never declare a global instance of a class that has a constructor.
 Not everything is as class.  Use them only when you gain something.
2.1 Class vs. Struct
In C++, a struct can also have member functions and operators and everything else that a class can have.  In fact, the only difference between a class and a struct is that all members default to public access in a struct but private access in a class.  However, we will not use this as the deciding point between using a class vs. a struct.  To match the normal intuition, we will use a class if and only if there are member functions included.
Summary:
 Use a class instead of a struct if and only if there are member functions.
2.2 Public, Private, and Protected members
As stated above, structs default to public access and classes default to private access.  However, we will depend on the default only in the case of structs (where we leave all the data implicitly public).  For a class, we will declare all members (both data and code) explicitly as public, protected, or private, and group them into sections in that order.  For example:
class Foo
 {
public:
 Foo();
 ~Foo();
 void Hey(int I);
 void Ack();
protected:
 int m_iValue;
private:
 int m_iStuff;
 void LocalHelperSub();
 };

Summary:
 Declare all class members explicitly as public, protected, or private, in groups in that order.
2.3 Data Members
Data members should use the naming convention m_name where name is a normal Hungarian local variable name.  This makes member function implementations easier to read (no confusion about member vs. local data), and allows the use of the same Hungarian name for, e.g., parameters and members.  See the example below.
Data members should normally not be declared public because this usually defeats the purpose of the class abstraction.  To efficiently export a data member, declare inline get and set member functions.  This will get optimized into the same code as a public data member.  For example:
class Counter
 {
public:
 int CItems() const { return m_cItems; }
 void SetCItems(int cItems) { m_cItems = cItems; }
private:
 int m_cItems;
 };

Summary:
 Data members use the naming convention m_name.
 Do not declare public data members.  Use inline accessor functions for performance.
2.4 Virtual Functions
Virtual functions are used to allow derived classes to override a method in a base class by providing their own implementation in a way that always causes the most-derived version to be called whenever a method is called through an object pointer, even if that pointer is declared as a pointer to the base class.  This is usually done to implement polymorphism, and that抯 when we抣l use them.  For example, all COM interface methods are virtual because you are always going for polymorphism via a standard interface.
Unlike simple member functions, virtual functions incur some overhead due to need to call through the vtable.  If a class contains at least one virtual function then the data size of each instantiated object will be 4 bytes larger than the combined size of the declared data in order to hold the vtable pointer.  After the first virtual function, each additional one only adds another entry to the class vtable, which is static and per-class (nothing per object), so the main concern here is whether a class has any virtual functions at all.  In addition to the memory overhead, there is the overhead to indirect a pointer twice before calling the function.  This is fairly fast and compact in 32-bit code, but affects speed and size nevertheless. Perhaps the worst part is that virtual functions cannot be inlined, so there will always be a function call, even when the work is trivial. 
Because they have overhead, you should not use virtual functions in a class unless you need to.  However, make sure you do use them when it makes sense.  In particular, if you have a base class which requires a destructor, then the destructor should definitely be virtual to allow derived classes to destruct any added members properly.  If the destructor were not virtual, then in a context where polymorphism is being used (so the object pointer is declared as a pointer to the base class), the base class destructor will always get called, even for an object of a derived class that added data members and declared its own destructor in an attempt to free them.  The derived class抯 destructor will only get called if the base class destructor is declared virtual.  This scenario applies to many other kinds of methods that you will add to your classes.  In fact, most of the methods in a base class might be this way if polymorphism is intended.  This issues is discussed in more detail in the Inheritance section below.
Note that although virtual functions have a performance penalty over regular member functions, they are often the most efficient way to implement a concept such as polymorphism where the alternative would be large switch statements (not to mention the benefits of the object-oriented encapsulation).
Summary:
 Use virtual functions to implement polymorphism.
 Virtual functions have overhead, so don抰 use them unless you really should.
 A destructor in a base class should always be virtual if polymorphism is intended.
2.5 Constructors
Ah, constructors.  Every new C++ programmer抯 nightmare.  This is one reason to try to minimize the use of constructors -- C programmers aren抰 used to them and will get confused.  Another reason is the infamous performance overhead of calling a function (unless it抯 inline) and doing work at possibly unexpected and/or redundant times.
However, using constructors can eliminate the dangers of uninitialized data and can also made the code simpler to read (if you抮e used to it).  Judicious use of destructors (see below) which match the constructors can also help prevent memory leaks and other resource management problems.
Fortunately, the issue is mainly one when classes are declared on the stack or passed by value, both of which we will avoid.  Most of our classes should be dynamic memory objects  which will be passed around by pointer.  In this case, the constructor is essentially just a helper function for the functions that create these dynamic objects.  Using a constructor for this purpose is reasonable to ensure a clean and consistent initialization (if you make sure to initialize all data members), but to prevent potential performance problems due to redundant initialization the constructor should not do anything expensive.  Simply assigning a constant or a parameter value to each data field is about right.  Very simple constructors can be made inline. 
Most importantly, a constructor should never be able to fail, because lacking a fancy exception handling mechanism, the caller has no way to handle this in some cases.  Any initialization that can fail (e.g. memory allocations) should be put in a separate initialization member function (called, e.g., FInit).  When this is the case, it is often useful to encapsulate the creation of an object in a function (a global function or a member of another class) that calls new and then FInit for the object, and returns the result of FInit.  For example:
class Foo
 {
public:
 Foo(int cLines) { m_hwnd = NULL; m_cLines = cLines}
 virtual ~Foo();
 BOOL FInit();
 void DoSomething();
private:
 HWND m_hwnd;
 int m_cLines;
 };

BOOL FCreateFoo(int cLines, Foo **ppfoo)
{
 if ((*ppfoo = new Foo(cLines)) == NULL)
  return FALSE;
 if (*ppFoo->FInit())
  return TRUE;
 delete *ppFoo;
 *ppFoo = NULL;
 return FALSE;
}

BOOL Foo::FInit()
{
 m_hwnd = CreateWindow(...);
 return (m_hwnd != NULL);
}

Summary:
 Do not do expensive work in a constructor.
 If you do make a constructor, make sure to initialize all data members.
 Very simple constructors can be made inline
 A constructor should never fail.  Do memory allocations and other potential failures in an FInit method.
 Consider making a creation function that encapsulates the new and FInit operations.
2.6 Destructors
If a class has resources that need to be freed, then the destructor is a convenient place to put this.  The normal case for us will be that this is just the central place to free resources for an object that is freed via delete (see below).  The trickier use of destructors is for stack-allocated classes, but we抮e going to avoid that by not using classes on the stack. 
A destructor should be careful to destroy an object properly regardless of how it was created or used.  Furthermore, if you choose to implement a method that frees any resources before the actual destruction, make sure to reset those fields (e.g. set pointers to NULL) so that a destructor will not try to free them twice.  It is not necessary for the destructor to reset any fields, though, because the object cannot be used after it is destructed.
Like a constructor, a destructor can never fail.  Also, as stated above, a destructor in a base class should always be declared virtual to make polymorphism work.
The destructor for the above example would be defined as:
Foo:~Foo()
{
 if (m_hwnd != NULL)
  DestroyWindow(m_hwnd);
}

Summary:
 Use a destructor to centralize the resource cleanup of a class which is freed via delete.
 If resources are freed before destruction, make sure the fields are reset (e.g. set pointers to NULL) so that a destructor will not try to free them again.
 A destructor should never fail.
 A destructor in a base class should always be declared virtual if polymorphism might be used.

Office通用OA系统源代码 除了具有传统OA的邮件、工作流、文档等功能外,还引进了项目管理和知识管理的思想,更加注重工作任务的分解、协同和监督;知识的积累、沉淀和分享,多条件跳转的分支流更为特色,有效为企业构筑协同工作平台 我的任务:今天未完成任务列表 我的邮件:最新收到的邮件列表 我的文档:最新归档的项目文档 我的审批:待我审批的项目文档 考勤:成员上下班的考勤 全文检索:对系统中项目文档的全文检索,并有权限过滤机制 系统设置各类接点:系统的权限中心和配置中心 人员管理:系统账户;由系统管理员添加、修改;可以定义新增、离职、调职还可自定义查询 职位管理:组织内的职位结构树,是权限的基本结构 角色管理:权力的集合,可以自由定义。系统默认的有组长、组员和系统成员。 修改口令:成员修改自己的口令(系统管理员在成员模块中修改口令) 考勤查询:查询包括自己在内的考勤纪录,或系统指定的成员如人事助理可查全部成员 考勤设置:考勤日和考勤时间的设置 公司论坛:包括公司公告和各版块BBS;有BBS管理权可以添加桌面公告和版块公告,版主可以自由添加版块和版块公告。BBS的功能同常见的,但无须登录; 客户管理(客户接触点的管理) 我的客户:显示由我负责的客户信息,并添加接触纪录(电话、拜访等) 查询、统计:客户资料的统计和分析,销售人员的业绩管理 我的联系人 公司内部联系人:系统成员列表中获得 公司外部联系人:等同于公司客户的联系人 自定义联系人:管理私人的联系人 我的任务:(含任务协同、任务指派、任务查询) 待完成任务:显示今日往后的未完成任务,并对任务操作,如新建、取消、完成、接受 未完成任务:显示今日以前的未完成任务 已完成任务:显示完成的任务 我的发起任务:显示所有我发起的任务,其中包括我仅发起而不执行的指派任务 订阅/查询任务:显示我不参加的任务,查询他人的任务 我的邮件 收件箱:我收到的邮件,全部显示 发件箱 :我曾经发送的邮件,全部显示 废件箱 :我删除的收到过的的邮件 撰写新邮件:可以有项目属性,并可归档 公文流转 待批文档:流程走到我这里的文档,等待我处理 我的申请:我发起的流转申请 已批文档:从我这里过的,被我处理过的文档 流程管理:由我创建和管理的流程,需要制定环节和绑定角色 拟稿箱:我可以发起的文档流转的入口,凡流程的第一环节有我的,都显示;并可以对流程有条件查询 我的文档 已归档:我可以查看的已归档项目文档 待审批:正等待我审批的项目文档;审批权包括角色指定,或是项目组长。 公司项目:项目树的管理,每人看到自己参与的项目内容或权限赋予的内容 投递文档:对该项目投递相关的文档 撰写邮件:对该项目组成员发送邮件 项目管理:项目的创建、删除、修改、移动 成员管理:项目成员的添加、删除;组长的标记;组员权限的变更 项目订阅:显示我关心的项目内容(本人并不是项目成员,但有权查看) 目录管理:创建项目文档库,并有严格权限限制,文档目录可扩展 短信管理: 站内短信:系统内的消息机制 站外手机短讯:发送多个附加手机号码 USB_Key 设置:对硬件加密的设置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值