首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

C++代码轨范和风格

2012-07-28 
C++代码规范和风格代码规范注释文件头类类说明在类声明之前 方法和变量1.使用C风的注释方式, C语言的/*…*/

C++代码规范和风格
代码规范

注释
文件头
C++代码轨范和风格

类说明在类声明之前

 C++代码轨范和风格

方法和变量

1.  使用C++风格的注释方式, C语言的/*…*/方式避免使用

C++代码轨范和风格

2.  大量代码的注释使用宏定义

C++代码轨范和风格

3.  枚举类型

C++代码轨范和风格

分隔带
////////////////////////////////////////////////////////////////////////////////////////////
头文件规则

1.  头文件包含h, hxx和inl,分别表示

*.h   :  Header File

*.hxx :  Private Header File

*.inl  :  Inline File

2.  头文件以文件头注释开始[参考注释小节的文件头]

3.  之后为防止多次编译的宏定义和命令行

4.  头文件需要包含的其他文件[*.inl不能包含其他文件]

#include <XXX>   ---  包含系统级别的头文件

C++代码轨范和风格

#include “XXX”   ---  包含项目级别的头文件

C++代码轨范和风格

5.  命名空间

6.  为保证头文件的整洁明了, 内联的请尽量在*.inl文件中完成, *.inl放在最后

7.  头文件可以只声明一个类, 也可以按关系需要声明多个类

8.  以下是一个头文件按1-7条的模版

/////////////////////////////////////////////////////

//   Volcano Orca Lord(VOL) SDK                    //

//   Copyright(C) VOL Studio. All RightsReserved  //

//   Header File : codec.h                         //

//   Author : orca.vol@gmail.com                   //

//   Create : 2007-03-06     version 0.0.0.1       //

//   Update : 2012-02-28     version 0.0.4.8       //

//   Detail : codec                                //

/////////////////////////////////////////////////////

#ifndef __CODEC_H__

#define __CODEC_H__

 

#pragma once

#include "tstring.h"

///////////////////////

namespace VOL       //

{                    //

///////////////////////

 

////////////////////////////////////////////////////

// CBase64

#ifdef
0

class NOVTABLE CBase64 :public MObject

{

public: 

    static bool Encode(CString& strIn,CString& strOut); 

    static bool Decode(CString& strIn, CString& strOut);

};

#endif

////////////////////////////////////////////////////

#include "codec.inl"

 

///////////////////////

} // namespace VOL   //

///////////////////////

 

#endif //__CODEC_H__


源文件规则

1.  源文件包含cpp和cxx, 分别表示

*.cpp :  Source File

*.cxx :  Private Source File

2.  源文件以文件头注释开始[参考注释小节的文件头]

3.  源文件需要包含的其他文件

#include <XXX>   ---  包含系统级别的头文件

#include “XXX”   ---  包含项目级别的头文件

4.  使用命名空间的语法说明

5.  源文件内容

6.  以下是一个头文件按1-5条的模版

/////////////////////////////////////////////////////

//   Volcano Orca Lord(VOL) SDK                    //

//   Copyright(C) VOL Studio. All RightsReserved  //

//   Private Source File : streamfile.cxx          //

//   Author : orca.vol@gmail.com                   //

//   Create : 2007-03-06     version 0.0.0.1       //

//   Update : 2012-02-28     version 0.0.4.8       //

//   Detail : codec                                //

//                                                //

/////////////////////////////////////////////////////

#include"inc.h"

#include"memmgrdef.hxx"

#include"platform.hxx"

#include"memaid.hxx"

#include"streamfile.hxx"

 

///////////////////////

usingnamespace VOL; //

///////////////////////

 

/////////////////////////////////////////////////////

// CFileReadStream

ULLong CFileReadStream::Read(void* pV, ULLong ullLenBytes)

{

     //…

}

 

命名规范

请按照微软的匈牙利命名规范

 

注意和建议

代码规范对刚开始实行可能会有所不习惯, 但给予团队内部代码可读性和维护性而言是个极大的提高, 所以请先努力按规范编写代码, 为高质量完成项目打下基础

 

代码风格

如果说代码规范是团队制定的统一代码标准的话, 代码风格就可以理解为是C\C++语言效率上提高的统一经验积累.

 

代码风格的重要性

纵观计算机语言的发展, 我们提取出每个时期的代表语言,

1.  二进制编码

2.  汇编语言

3.  C语言

4.  C++语言

我们从代码执行效率上去判断, 可以认为上面的先后顺序: 1 = 2 >= 3 >= 4, 语言的发展反而使执行效率降低了, 但是, 效率的牺牲, 换来的是更高的提升:

1.  代码的可读性

2.  代码的可维护性

3.  代码质量

4.  开发效率

 

我们要讨论的风格, 就是在遵循上面提升的基础上, 让语言的执行效率能保持最优化而言的.

 

代码风格的重点

C\C++语言是一种自由度很高的语言, 我们不可能全面的去讲解每个知识点, 这里提取出最重要也是最常用的亮点来讲解:

1.  指针有关

2.  类有关

指针有关

和指针有关的, 就是指针变量和其指向的内存之间的关系了, 这个也是所有使用C\C++最最容易出问题的地方. 有人说, 反正程序能跑完, 所有泄露的内存都会被系统回收的, 这个观点是没错误, 但是我们要考虑到如果是服务器程序, 开了就需要运行几年的, 不知道那天,所有内存被你的程序吃完了, 又或者临时变量将栈耗光了, 你的程序还能跑完吗?

 

所以, C\C++语言, 指针和内存的关系永远是重点. 从指针的内存申请方式, 可以简单的归纳为以下3种:

1.  静态存储的, 一般为全局变量或者类的静态成员变量

2.  从栈(stack)中申请的临时内存, 临时类对象, alloca的申请

3.  从堆(heap)中申请的,malloc或者new

 

上面3中情况, 1和2有系统自动回收指针变量对应的内存空间, 我们可以不用关注; 我们的重点是第3种情况, 这种情况下, 请永远记住以下的检测过程:

1. 指针变量出作用域变无效   ≠  指针变量指向的内存被释放

2. 指针变量指向的内存被释放 ≠  指针变量变无效(NULL)

 

举个例子:

void Convert(char* pszTxt)

{

     int   nLen = strlen(pszTxt);

     char*pszTmp =new char[nLen+ 1];

     for(int i = 0; i < nLen; ++i)

     {

         pszTmp[i] = pszTxt[nLen - i- 1];

     }

     pszTmp[nLen] = 0;

     pszTxt= pszTmp;

// void control::GetContent(char*& p);

// 获取控件的内容,不会失败

void MyForm::Function(...)

{

    char*pTemp = NULL;

    control.GetContent(pTemp);

     //…

    Convert(pTemp);

    control.Update();

}

对于指针变量和对应的内存, 我们在开发中要注意的风格是:

1. 判断申请内存返回情况, 内存耗尽了的情况还是有一定几率存在的

2. 指针变量初始化, 不要变成野指针

3. 指针变量的作用域

4. 指针变量指向的内存被释放, 建议将指针变量设计为NULL

 

 

类有关

类有关的代码风格, 我们可以参考Effective C++

这里重点讲解以下几个点:

1.  类的复制构造方法和赋值操作符[EC++, item 11]

2.  类的初始化列表[EC++, item 12, 13]

3.  基类的虚析构方法[EC++, item 14]

4.  C++风格的类型转换

 

复制构造方法和赋值操作符

1.  我们以一个简单的String开始举例讲解:

class String

{

public:

      String(constchar* value);

      ~String(void);

private:

     char*data;

};

inline String::String(constchar* value)

{

     if(value != 0)

     {

          data = new char[strlen(value)+ 1];

          strcpy(data, value);

     }

     else

     {

         data = new char[1];

        *data = '\0';

     }

}

inline String::~String(void)

{

    delete[]data;

}

 

以下代码执行:

//...

string a("hello");                // 定义并构造a

{                                 // 开一个新的生存空间

  string b("world");              // 定义并构造b

  //...

  b = a;                          // 执行operator=, 丢失b的内存

}                                 // 离开生存空间, 调用b的析构函数

string c = a;                     // c.data 的值不能确定, 因为a.data已被删除

//...

在没有进行第一次赋值操作之前:

C++代码轨范和风格

在进行第一次赋值操作之后:

C++代码轨范和风格

当b对象被释放, b原来申请的内存没被释放, 反而将a对象的内存释放了, 这个时候a对象的指针变量变成了野指针[默认的赋值操作代码由编译器帮我们简单的实现了]

 

再看下面的代码:

//void donothing(string b)

//{

//   // ...

//}

 

string a = "the truth is out there";

donothing(a);

 

当方法donothing调用完成, a对象的指针变量变成野指针

C++代码轨范和风格

donothing虽然什么都没做, 但是调用它时, 生成了一个临时对象b, 当b出donothing方法作用域也就不存在了, 当b对象被释放, 将a对象的内存释放了, 这个时候a对象的指针变量变成了野指针[默认的复制构造代码由编译器帮我们简单的实现了]

 

2.  在看下面例子

class base

{

public:

    base(inti = 0);

    virtualint getval(void)const;

private:

    intdata;

};

inline base::base(int i)

: data(i)

{

}

 

inline int base::getval(void)const

     returndata;

}


class derived :public base

{

public:

    derived(inti = 0,int j = 0);

    virtualint getval(void)const;

private:

    intvalue;

};

inline derived::derived (int i,int j)

: base(i)

, value(j)

{

}


inline int derived::getval(void)const

{

     return(base::getval() + value);

}

 

再看下面的代码:

void report(base b)// 系统默认在调用中帮我们生成了一个base类型, 不管实际对象是哪个

{

    printf("the value is = %d\n", b.getval());

}

void main(void)

{

    base      b(10);

    derived   d(10, 51);

   

    report(b);   // OK

    report(d);  // ?

 

}

C++代码轨范和风格

 

对于类的复制构造和赋值操作符, 我们在开发中要注意的风格是:

1. 类对象传递使用引用

2. 如果不想实现类的复制构造和赋值操作符, 请将它们声明为私有

3. 将基类虚析构直接声明为纯虚方法, 防止使用者参数不是引用类型时的安全

 

 

类的初始化列表

类的初始化列表初始化效率比在类的构造方法里要好

类的初始化类表初始化变量顺序应该按变量声明的顺序来排列

 

1.  例子

class name

{

public:

  name(constchar*str1, const char*str2);

private:

  String strName;

    String strAlias;

};

// 1

name::name(constchar*str1, const char*str2)

{

  strName  = str1;

    strAlias = str2;

}

// 2

name::name(constchar*str1, const char*str2)

: strAlias(str2)

, strName(str1)

{}

// 3

name::name(constchar*str1, const char*str2)

: strName(str1)

, strAlias(str2)

{}

 

建议使用3

 

虚基类析构方法

例子:

class base

{

public:

     base(void);

     ~base(void);// virtual ~base(void);

};

inline base::base(void)

{

     printf("Inbase()\n");

}

inline base::~base(void)

{

     printf("In~base()\n");

}

 

class derived :public base

{

public:

     derived(void);

     virtual~derived(void);

private:

     char*data;

};

inline derived::derived(void)

{

     data = newchar[STR_LEN_MAX];

     assert(data != 0);

     data[STR_LEN_MAX - 1] = 0;

}

inline derived::~derived(void)

{

     printf("In~derived()\n");

     assert(data != 0);

     delete[]data;

}

 

 

看以下代码:

void kill(base* pb)

{

     deletepb;

}

int main(void)

{

     derived * pd = new derived;

     assert(pd != 0);

     kill(pd);

     return0;

}

基类请尽量使用虚析构方法

 

 

C++风格的类型转化

const_cast

reinterpret_cast

static_cast

dynamic_cast

 

 

1楼Wentasy3天前 18:46
收藏了。

热点排行