2007年01月15日 星期一 12:44

编写C++/C代码规则
参考书目《高质量C++/C编程》(林锐著)
能长期稳定地编写出高质量程序的程序员称为编程老手。
能长期稳定地编写高难度高质量程序的程序员称为编程高手。
※知错就改;温故知新;坚持学习,天天向上
规则
★为了防止头文件重复引用,应当用ifndef/define/endif结构产生预处理块。
★用include<filename.h>表示引用标准库的头文件;用include "filename.h"引用非标准库的头文件。
?★头文件只存放“声明”而不存放“定义”;不提倡使用全局变量,不要在头文件声明,分目录放置;如果头文件是私有的,为加强其隐蔽性,存放在子目录中。

★类声明之后,每个函数定义之后都要加空行。
★逻辑密切相关的不加空行,其他的地方应加空行。
★一行代码只做一件事。
★if,for,while,do等语句各自占一行,执行语句不得紧跟其后。无论执行语句有多少都要加{}。
★变量定义时初始化。
★关键字之后要留空格,函数名之后不留空格。
★“{”和“}”独占一行与引用它们的语句左对齐。
★“{}”内语句在右边数格处左对齐。
★代码行(hang)为一屏幕能显示下的长度。
★长代码表达式在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当缩进,使排版整齐语句可读。
×将修饰符*和&紧靠变量(不同意!既然都不允许int* x,y的声明方式,为何不靠近数据类型!)
★注释是代码提示,不是文档(象我,在没有条件写文档的情况下只能拿注释当文档!)注释与代码一直,没用的注释及时删除。注释放在代码上方!
★★尽量使结构清晰,避免繁琐的注释。
★★多重嵌套结束处加注释,便于阅读。
★★标识符应当直观可拼读,长度应符合“min-length&&max-informatrion”原则。
★★与所采用的OS或开发工具的风格保持一致。
★不要靠大小写区分相似的标识符。
★★不要出现完全相同的局部变量和全局变量。
★变量名使用“形容词+名词”。
★★全局函数名使用“动词”+“名词”;类成员函数名只使用“动词”。
★★用正确的反义词表互斥的变量或相反的动作函数。
★windows程序开发“匈牙利”命名规则
  类名和函数名首字母大写
  变量和参数用小写字母开头的单词组合而成
  常量全部大小用下划线分割单词
  静态变量s_,全部变量g_,类的类数据成员m_。
★★对于unsigned的变量加入un前缀,对于常用的,并且通过变量名称如:(size len 等)容易推断出的变量不加前缀
★代码行中符号较多,用括号确定其优先级。
★复合表达式不要太复杂,不要多用途,不要与数学表达式混淆。
★不可将布尔变量与TRUE,FALSE或者1,0进行比较。
★将整形变量用“==”或“!=”直接与0比较。
★不可将浮点变量用“==”或“!=”与任何数字比较。
★指针变量用“==”或者“!=”与NULL比较。
★if的条件可写成if(NULL == p),注意。
★★只有==使用变量在右的方式,!=、 >、 >=、 <、 <=条件不使用变量在右的方式
★注意使用其简单模式:condition?x:y。
★★长循环在最内,会提高循环效率。
★逻辑判断套循环效率高,但不易理解,不易修改。
★★不可在循环体内改变循环变量。
★for循环采用半开半闭区间写法for(i=0;i<N;i++)。
★每个case语句后都要加break。
★不要忘记default分支。
★多重嵌套可使用goto跳出。
★★函数很多返回,且返回之前要释放堆上申请的内存或关闭文件等操作,可使用goto返回位置。
★★使用含义直观的常量表示程序中多次出现的数字或字符串。
×在C++中只使用const不使用#define。
★需要对外公开的常量放在头文件中,不需要公开的放在定义文件的头部;用户看得见的放在一个公共的头文件中,便于管理。
★★定义中应表现出关系密切的常量间的关系。
★类中常量应用enum{SIZE1=100, SIZE2=200}。
★参数的书写要完整(类型 名字);无参数应写void(声明中用void)。
★★参数要命名恰当,顺序合理。
★如果参数是指针,且反作输入用,应在类型前加const,以防在函数内被修改。
★值传递,传递对象时应用const& 方式省去临时对象的构造和析构过程,提高效率。
★★参数最好控制在五个以内,尽量不使用类型和数目不确定的参数。
★不要省略返回值类型。
★★函数名和返回值在语义上不可冲突。
★返回对象时使用“引用传递”可提高效率,但有些场合会出错。
★★在函数体的“入口处”对参数的有效性进行检查—正确使用断言(assert)。在函数体的“出口处”对return语句的正确性和效率进行检查。不能返回指针“栈内存”的“指针”或引用 返回的是“值”,“指针”还是“引用”。返回值是个对象,要考虑return的效率。
★★函数应功能单一,50行代码以内,避免“记忆”(static)功能,检查全局变量,文件句柄等,出错处理的返回值一定要清楚。
★★assert不仅说明非法错误还要说明非法错误的原因!
★★对参数合法性的判断:assert()只适用自己和团队内部调用的函数,是一种“约定”的检查,对外提供的函数接口不应使用assert(),应用if替代。

内存分配方式:静态存储区域,在栈上创建,从堆上分配。
内存错误以及对策:内存未分配成功却使用它,使用之前检查指针是否为NULL
分配成功却未初始化却使用了;赋初值
忘记释放内存,new/delete malloc/free成对出现
释放了却还使用:数据结构不合理,重新设计;return用错;野指针
修改指向静态存储区的指针中的内容将出错
数组用库函数strcpy(),strcmp()进行复制和比较
指针内容比较,先申请len+1个空间内存在用strcpy比较 sizeof(数组)计算数组的容量sizeof(指针)计算指针变量的容量 数组作为函数的参数进行传递时,数组自动退化为同类型指针,不要用指针参数申请动态内存,如果必须应用指向指针的指针 指针与其所指向的内存的消亡是没有联系的
new/delete对对象比malloc/free多调用构造和析构函数
内存耗尽指针将返回NULL;用return返回;用exit(1)终止程序
异常处理如 vc++中_set_new_hander函数?
malloc的使用:int* p = (int *)malloc(sizeof(int) * length);
free的使用free(NULL)没有问题,free(p)且p!=NULL二次将出错
new数组对象时,delete[]数组释放
重载 小心隐式类型转换
重载,隐藏,覆盖
参数缺省值只出现在函数声明中,多个缺省值从后向前挨个缺省
重载运算符
×内联取代宏代码,内联放定义处;代码长,有循环不易inline。inline会对栈溢出的排错造成困难
一定要写无参数构造函数,拷贝构造函数,析构函数,赋值函数,偷懒时候可将其声明为private
若逻辑上B是A的“一种”,并且A的所有功能和属性对B而言都有意义,则允许B继承A的功能和属性
use const whenever you need!


标签: cplusplus
日期: 2016-09-09 17:30:06, 8 years and 128 days ago

原文

红黑树与哈希表比较:

  • 哈希表操作不够清楚。
  • 红黑树插入,删除,查找速度可均摊。
  • 在最坏情况下,树有更好的性能。

这大半是因为一个历史意外。在标准规则被确定之前,标准容器(包括迭代器和算法)很晚才被加入。所以,在标准确定之前,没有充分考虑到哈希表的定义,并且也没有足够时间加入。所以标准只包括了一个基于树的map。

C++11 加入了基于hash的std::unorderedmap(以及std:unorderedset)。

标签: cplusplus
日期: 2016-07-21 17:30:06, 8 years and 178 days ago


2007年01月15日 星期一 12:33

快速学习C++

其中*为需要重点注意
《Essential C++》侯捷译 Stanley B. Lippman著

一、C++基础
 1、撰写C++程序
 ////////////////////////////////////////
 #include <iostream>
 using namespace std; //让命名空间暴光
 int main
 {
   cout<<"hello,C++"<<endl;
 }
 ///////////////////////////////////////
 如果main()函数的最后没有return语句,C99规定编译器要自动在生成的目标文件中(如 exe 文件)加入return 0;表示程序正常退出。
 2、对象的定义与初始化 ??※const的应用
 3、撰写表达式
 4、条件语句和循环(Loop)语句
  if (条件)
  {
   ...
  }
  else
  {
   ...
  }
  while (条件)
  {
   ...
  }
 5、数组 Arrays off-by-one 越界(数组array[n]从array[0]开始,最后一个为array[n-1])
 6、指针带来的弹性 *取值 &取地址
 7、文件的读写
  #include <fstream>
  ofstream outfile ("seq_data.txt"); //写文件
  ofstream outfile("seq_data.txt", ios_base::app); //追加形式开启
  ifstream infile("seq_data.txt"); //读文件
  fstream iofile("seq_data.txt", ios_base::in|ios_base::app); //读写

二、面向过程的编程风格
 1、撰写一个函数
  int function(int x, int *y)
  {
    ...
    return 0;
  }
 2、调用(invoking)一个函数
 3、提供默认参数值
 4、使用局部静态对象 const
 5、声明一个inline函数
 6、提供重载函数
 7、定义并使用模版函数
  template<typename elemType>
  int function(const int x, const elemtype y)
  {
    ...
  }
 8、函数指针 vector<int>* (*seq_pstr)(int);
 9、枚举类型 enum ns_type{ns_fibon, ns_lucas, ns_pell};
 10、设定头文件

三、泛型编程风格
 1、指针的算术运算 int* pi;pi+2的意义
 2、???Iterators泛型指针
  vector<string> svec;
  vector<string>::iterator iter=svec.begin();
 3、所有容器通用的操作
  equality() ==
  inequality() !=
  assignment() =
  empty()
  size()
  clear()
  begin()
  end()
  insert()
  erase()
 4、使用序列式容器
 5、使用泛型算法
 6、如何设计一个泛型算法
 (1)开始我们写了一个函数,它可以找出vector内小于10的所有元素,然而函数过于死板没有弹性。
 (2)接下来我为函数加上一个数值参数,让用户得以指定某个数值,以此和vector中的元素做比较。
 (3)后来我又加上一个新函数:一个函数指针,让用户得以指定比较方式。
 (4)然后我引入function object的概念,使我们得以将某组行为传给函数,此法比函数指针的做法效率更高,我们也带领各位简短地检阅了标准函数库提供的function object(所谓function object,是某种class的实体对象,这类classes对function call运算符进行了重载操作,如此一来,可使function object被当成一般函数来使用)[函数指针,指向函数]
 (5)最后我们以template function的形式重新实现。为了支持多种容器,我们传入一对iterators,标出一组元素的范围;为了支持多种元素型别,我将元素型别参数化也将施用于元素身上的“比较操作”参数化,以便得以同时支持函数指针和function object两种方式
 3、TMap使用
  map<string, int> words;
  words["verneer"] = 1;
  map<string, int>::iterator it;
  it->first;
  it->second;
  words.find(); //如果key已置于其中,find()会返回一个iterator,指向key/value形成一个pair;反之则返回end()
  words.count(); //返回某特定项目在map内的个数
 set 由一群keys组合,对于任何keys值,set只能存储一份
  set<int> iset
   iset.insert(ival);
   iset.insert(vec.begin(), vec.end());
 如何使用Iterator Inserters
  #include <iterator>
  back_inserter();
  inserter(vector, iterator);
  front_inserter();

四、基于对象的编程风格
 1、如何实现一个class
 class Jack
 {
 public:
  //...
 private:
 //...
 }
 2、constructor和destructor
 3、const
 4、this指针
 5、static class member静态的类成员 类名::静态成员函数
 6、iterator class
 7、friend class友元类
 8、copy assignment operator
 9、function object
 10、运算符重载
 11、指向类成员函数的指针
五、面向对象编程风格
 (1)概念:继承、多态、动态绑定
 (2)面向对象思维
 (3)不带继承的多态*
 (4)定义一个抽象基类:找出所有子类共通的操作行为->哪些操作与型相依(是否为virtual)->每个操作行为的存取层次(是public还是private还是protected)
 (5)定义一个派生类*
 (6)使用继承体系:将所有派生类共有的实现内容抽离出来,移至基类内
 (7)基类抽象:从子类中抽象出基类
 (8)初始化、析构、复制 子类数据成员=基类data member+本身data member
 (9)在派生类中定义一个虚函数 继承 虚拟函数的静态决议->派生时完全吻合
 (10)执行期型别鉴定机制*

六、以template进行编程
 1、被参数化的型别
 2、class template的定义
 3、template型别参数(type parameters)的处理
 4、实现一个class template
 5、一个以function template完成的output运算符
 6、常量表达式(constant expressions)默认参数(Default Parameters)
 7、Template参数
 8、member template funtions

七、异常处理*
标签: cplusplus
日期: 2016-06-10 17:30:06, 8 years and 219 days ago

function declaration with throw

  • void f() throw() // no exceptions allowed 不允许抛出任何异常
  • void f() throw(...) // all exceptions allowed 允许抛出任何异常

  • void f() throw(type) // only the exception of type type allowed 只允许抛出type类型的异常

标签: cplusplus
日期: 2016-05-13 17:30:06, 8 years and 247 days ago

从visual C++.NET 2002(VC 7.0)开始,一些存在于MFC的基础类被重写和修订,削减了与 其他MFC类之间的关系。这些类库可以独立被用于任何的native C++工程。

  • CFileTime
  • CFileTimeSpan
  • CFixedStringT
  • CImage
  • COleDateTime
  • COleDateTimeSpan
  • CPoint
  • CRect
  • CSimpleStringT
  • CSize
  • CStrBufT
  • CStringData
  • CStringT
  • CTime
  • CTimeSpan
  • IAtlStringMgr
CSimpleStringT
 |
 +--CStringT
     |
     +--CFixedStringT

测试代码

例子

https://github.com/codepongo/utocode/tree/master/windows/independentmfc

int 
main(int argc, char* argv[])
{
    /* string */
    CStringT< char, StrTraitATL< char, ChTraitsCRT< char > > > str;
    str = "hi";
    str += ",independent MFC!\n";
    printf(str);


    /* point size rect */
    CPoint pt;
    CRect rc;
    CSize sz;
    rc.left = rc.top = 0;
    rc.right = rc.bottom = 100;
    sz = rc.Size();
    pt.x = 10;
    pt.y = 10;
    printf("rect(%d, %d, %d, %d):(%d,%d) move (%d, %d)\n",
        rc.left, rc.top, rc.right, rc.bottom, sz.cx, sz.cy, pt.x, pt.y);

    /* time */
    CTime tms;
    CTime tm;
    str.Format("%04d-%02d-%02d %02d:%02d:%02d\n",
        tms.GetYear(), tms.GetMonth(), tms.GetDay(), tm.GetHour(), tm.GetMinute(), tm.GetSecond());
    printf(str);

    CFileTime ft;
    CFileTimeSpan fts;
    COleDateTime dt;
    COleDateTimeSpan dts;

    str.Format("%lld\n", ft.GetTime());
    printf(str);

    /* image */
    CImage image;
    image.Load(L"image.png");
    str.Format("width:%d height%d\n", image.GetWidth(), image.GetHeight());
    printf(str);

    system("pause");
    return 0;
}

对MFC无依赖

参考

ATL/MFC Shared Classes

Classes Shared by MFC and ATL

MFC Hierarchy Chart

CString模板结构解析

标签: cplusplus, windows
日期: 2014-01-10 17:30:06, 11 years and 6 days ago