个人经验,谨作抛砖引玉。欢迎共同探讨和批评指正!
===============================
2008/09/23
处理MFC的ClassView中没有定义的消息需要注意三个地方,如WM_SYSCOMMAND消息,可以接收系统菜单命令,但ClassView中没有,这时需要自己手动添加。
一、在dialog的cpp中添加MessageMap:
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)和END_MESSAGE_MAP()宏命令之间,加入:ON_WM_SYSCOMMAND()
二、在dialog的头文件中添加消息处理函数定义:
在// Generated message map functions
//{{AFX_MSG(CTestDlg)
和//}}AFX_MSG
DECLARE_MESSAGE_MAP() 之间加入:
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
三、在dialog的cpp文件中添加消息处理函数体:
void CTestDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
若不添加第一步,编译不会出错,但不会获取对WM_SYSCOMMAND消息的处理权。
2008/09/19
RecordSet的RecordCount一直以为只有0或正数,今天才知道还会为-1;ADO 无法确定记录数时,或者如果提供者或游标类型不支持 RecordCount,则该属性返回 –1。特殊常见的是,对仅向前游标,RecordCount 属性将返回 -1。今天就是用了adOpenForwardOnly才发现RecordCount为-1.
2008/09/18
Effective C++条款12:
类的const成员只能被初始化,不能被赋值。
还可以对类成员同时声明const和引用,这样就生成了一个在类外可以被修改而在内部是只读的成员。如constconst string& name; // 必须通过成员初始化列表
用成员初始化列表比在构造函数里赋值要好。这次的原因在于效率。
对象的创建分两步:
1. 数据成员初始化。(参见条款13)
2. 执行被调用构造函数体内的动作。
因此,当使用成员初始化列表时,只有一个string成员函数被调用。而在构造函数里赋值时,将有两个被调用。
条款13:
类成员是按照它们在类里被声明的顺序进行初始化的,和它们在成员初始化列表中列出的顺序没一点关系。
条款14:
当通过基类的指针去删除派生类的对象,而基类又没有虚析构函数时,结果将是不可确定的。实际运行时经常发生的是,派生类的析构函数永远不会被调用。
有些时候,你想使一个类成为抽象类,但刚好又没有任何纯虚函数。怎么办?因为抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以方法很简单:在想要成为抽象类的类里声明一个纯虚析构函数。
但这里还有一件事:必须提供纯虚析构函数的定义:
awov::~awov() {} // 纯虚析构函数的定义
这个定义是必需的,因为虚析构函数工作的方式是:最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。这就是说,即使是抽象类,编译器也要产生对~awov的调用,所以要保证为它提供函数体。
条款15:
当定义自己的赋值运算符时,必须返回赋值运算符左边参数的引用,*this。如果不这样做,就会导致不能连续赋值(w = x = y = z = "hello";),或导致调用时的隐式类型转换不能进行,或两种情况同时发生。
条款22:
不要通过值来传递对象,而要通过引用:
const student& returnstudent(const student& s)
{ return s; }
这会非常高效:没有构造函数或析构函数被调用,因为没有新的对象被创建。
这个原则在使用CString时得到有力的佐证,所有以(CString str;)的形式传递的字符串,调试时使用F7单步跟进都会发现先调用CString对象的拷贝构造函数。
条款28:
有些命名空间没有名字。这种没命名的名字空间一般用于限制名字空间内部元素的可见性。
条款30:
有一天你可能为了程序的性能还是不得不写返回值是某个访问级较低的成员的指针或引用。但同时,你又不想牺牲private和protected为你提供的访问限制。这种情况下,你可以通过返回指向const对象的指针或引用来达到两全其美的效果。
2008/09/16
static_cast,转换类型,用法:static_cast < type-id > ( expression ) ,该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。 C++推荐做法。编译器隐式执行任何类型转换都可由static_cast显式完成。
2008/09/10
打算填入容器的类,最好都准备一个默认构造函数
map <string,Myclass> testmap;
testmap["001"] = Myclass(100);//这里是先构造,再赋值;因此testmap["001"]时会调用MyClass的默认构造函数,构造一个对象,然后再调用Myclass(100);最后将Myclass(100)赋值给前面testmap["001"]里构造出的对象
2008/09/02
try catch(...) 捕获不到ASSERT(NULL);引发的异常;同事说只能catch到throw出来的异常。
MSDN说:If the exception-declaration statement is an ellipsis (...), the catch clause handles any type of exception, including a C exception
any type of exception,是不是ASSERT不是exception?
这个说法未经权威资料证实。
2008/08/29
WM_CTRCOLOR消息处理函数中可以设置static的字体,颜色,背景色,透明等样式。
2008/08/28
Window Macros
The following macros are used to create and manage windows.
GET_X_LPARAM GET_Y_LPARAM HIBYTE HIWORD LOBYTE LOWORD MAKELONG MAKELPARAM MAKELRESULT MAKEWORD MAKEWPARAM
这些宏可用与DWORD中取高低位
File Function
所有File相关API,FindFirstChangeNotification可以监视文件系统的变化,包括创建文件删除文件修改文件等。
System Information Functions
系统信息相关API,如GetWindowsDirectory
2008/08/02
_ASSERTE宏可以在ASSERT基础上报告错误信息,使用如_ASSERTE(("inconsistent IOB fields", stream->_ptr - stream->_base >= 0));
注意,中间的括号必须要有,括号将两个参数变为一个参数,否则编译出错。
使用timeGetTime可以获取毫秒级时间,但需要设置timeBeginPeriod(1);使用完后再timeEndPeriod(1);
2008/07/13
默认编译的boost库是不支持unicode编码的,即默认编译出来的regex不支持/u, fk!
boost::regex使用ICU来实现对unicode及unicode变种的支持,这需要在编译boost的时候指出是否使用ICU以及ICU所在的目录。否则编译出来的boost::regex不支持unicode编码。其中boost::wregex支持unicode编码的搜索,如果要搜索UTF-8、UTF-16、UFT-32编码的字符串,则要用boost::u32regex。注意boost::wregex只能支持unicode编码,不能支持uft编码。
部分匹配使用regex_research,全部匹配使用regex_match
2008/07/03
boost库中的tokenizer库可以支持字符串拆分?
"我以前经常在CSDN上看到有人问怎么把一个字符串按逗号分割成字符串数组。也许有些人很羡慕VB的split函数。现在,boost的tokenizer也有相同的功能了,如果我没记错的话,这个tokenizer还支持正则表达式,是不是很爽?",这是STLChina介绍Boost时的原话。
2008/06/05
stlport和标准stl会冲突,TMD,stlport会使用
#define std STLPORT
导致std namespace冲突。若用了dll,在两边可能会导致unresolved external symbol 错误。
我认为直接使用STLPORT::vector会比std::vector要好。避免调用标准stl
2008/06/05
在CppUnit自带的测试sample中,我调用了一个dll,该dll的方法使用了const byte类型传递参数,结果死活编不过去,改成USHORT,UINT就OK。
byte不是所有的地方都支持
2008/04/30
据网上消息,内码转换可以通过MultiByteToWideChar和WideCharToMultiByte函数实现,如Big5 => GBK转换。
int nReturn = MultiByteToWideChar(950, 0, szBuf, nStrLen, pws, nStrLen + 1);
nReturn = WideCharToMultiByte(936, 0, pws, nReturn, szBuf, nStrLen + 1, "?", &bValue);
2008/04/24
标准SQL语句不区分大小写,即ab=AB,因此select * from tab where field1="ab"会筛选出ab和AB。
2008/04/18
强烈反对用CString做CMap的key,效率比数字会降低N倍.
若是一个长整型数字字符串,以atol将字符串转为long型做key,比直接使用cstring做key要快很多,显然,long型可以直接比较,cstring需要一个字符一个字符比较才能实现map的自动排序.atol的效率损失在这几乎可以忽略了.
2008/04/11
如果文件是utf-8编码的话
前三个字节是0xEF 0xBB 0xBF
如果文件是unicode big endian(大端字序,即高位在前)编码的话
前两个字节是0xfe 0xff
如果文件是unicode little endian (小端字序,即低位在前) 编码的话
前两个字节是0xff 0xfe
2008/03/25
const _variant_t& CComboProp::GetValue() const
{
this->m_varValue.SetString(m_strValueArray.GetAt(m_nSeled));
return this->m_varValue;
}
编译出错:
error C2662: 'SetString' : cannot convert 'this' pointer from 'const class _variant_t' to 'class _variant_t &'
试图对一个const类型的类对象(m_varValue)调用非const型的成员函数(SetString)。
一般造成此问题的原因是,对m_varValue.SetString的调用是在一个const型的成员函数中进行的。对于const型的成员函数,编译器会将其引用的任何成员变量标记为const类型——虽然在类的声明中该成员变量可能不是,从而导致此错误。
2008/03/17
CString转换成CTime的两种方法:
方法一,使用CTime构造函数:
CString s("2001-8-29 19:06:23");
int nYear, nMonth, nDate, nHour, nMin, nSec;
sscanf(s, "%d-%d-%d %d:%d:%d", &nYear, &nMonth, &nDate, &nHour, &nMin, &nSec);
CTime t(nYear, nMonth, nDate, nHour, nMin, nSec);
方法二,辗转转换:
strCString="2003-10-27 6:24:37"; //CString--->COleDateTime
COleVariant vtime(strCString);
vtime.ChangeType(VT_DATE);
COleDateTime time4=vtime;
COleDateTime time1(1977,4,16,2,2,2); //COleDataTime--->CTime
SYSTEMTIME systime;
VariantTimeToSystemTime(time1, &systime);
CTime tm(systime);
2008/03/11
静态类成员变量的初始化在类外面。在所有类和函数代码外面初始化,如
class a
{
public:
static int b;
}
int a::b = 0; //如此初始化,不在任何类代码里面
2008/03/04
屏掉VC的一些编译警告信息,在StdAfx.h中加入如下代码,
#pragma warning(disable: 4146 4786)
将会屏掉ms ado库的4146号编译警告,同时屏掉使用stl模板库的4786号编译警告信息。
2008/01/22
VC操作菜单可用CMenu类,封装了很多菜单操作方法。例子如下:
CMenu* pMenu = this->GetMenu(); //获取窗体主菜单
pMenu->CheckMenuItem(IDR_MENU_FILE_PAUSE, true);//使菜单checked
2008/01/21
全局函数获取主窗口句柄的方法:
CWinApp* MainApp = AfxGetApp();
CWnd* MainWnd = MainApp->GetMainWnd();
((CTanchisheDlg*)MainWnd)->m_Config = NULL;
窗口句柄和窗口类可以强制转换通用.
2007/11/28
使用BCG的文件夹按钮时(EnableFolderBrowseButton函数),需要先调用CBCGPWorkspace::InitShellManager ();
靠,放在源码注释里...我程序崩溃时死活找不到原因... 真烂的招.
2007/10/19
继承自CDialog的对话框响应键盘事件。只要对话框上有子窗口就没机会响应到按键消息,因为按键消息被子窗口处理掉了,需要在PreTranslateMessage中过滤此消息。
BOOL CTanchisheDlg::PreTranslateMessage(MSG* pMsg)
{
if( pMsg->message>=WM_KEYDOWN && pMsg->message<=WM_KEYUP)
{
this->SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);
return TRUE;
}
else
return CDialog::PreTranslateMessage(pMsg);
}
2007/10/09
boost中的正则表达式regex使用regex_match后返回的cmatch中头个元素是整个式子的匹配结果.后面从1到cmatch.size-1是所有的子匹配项的结果.一定得注意,它的match和submatch并未分开.
2007/09/30
类中成员函数设为inline内联函数的话,必须把函数体也放到hpp头文件里,若放到cpp里会编译报错。
2007/09/18
自写创建多线程的例子代码:
LPDWORD lpThreadId;
HANDLE handle;
handle = CreateThread(NULL,//安全信息
0, //堆栈大小,0时使用和调用线程同样大小的堆栈
RunGame,//新线程调用函数的函数地址
this->m_Config,//线程函数的参数
CREATE_SUSPENDED,//线程创建后非马上执行,0 时马上执行
lpThreadId); //输出线程ID
if (handle == NULL)
{
MessageBox("创建游戏线程失败.", "错误", MB_ICONERROR);
}
207/09/06
用字符串常量给字符数组初始化时若字符数组大于或等于字符串常量长度+1,则编译器会自动在字符数组中增加'/0',否则会报数组溢出。
如有:
char a[] = "aaaa";
int b = sizeof(a) / sizeof(char); //b=5
若再有:
char a[4] = "aaaa"; //会报错:Array bound overflow
int b = sizeof(a) / sizeof(char);
内联函数(inline)必须在被调用之前声明或定义,因为内联函数的代码必须在被替换之前已经生成被替换的代码。否则编译时会报错
error LNK2001: unresolved external symbol
2007/09/03
set是有序集合,insert元素时会自动排序。erease时会自动清除元素所在内存。
2007/08/27
使用STL的vector时需要using namespace std;或者定义时使用std::vector<>来定义,否则编译时提示很奇怪的几个错误。完全粘不上边的几个错误。
2007/07/20
GetBuffer和LockBuffer函数使用后一定得ReleaseBuffer(),否则会内存泄漏.
2007/07/09
format输出百分号时需要两个百分号, a=10; format("%s%%",a); 得到10%
2007/07/04
SHCreateDirectoryEx相当于delphi中的ForceDirectories可以强制创建一个指定目录中的所有级不存在目录.Declared in shlobj.h.
2007/06/21
_itoa 整型转字符串,_atoi字符串转整型, ltoa 长整型 _fcvt 浮点数转字符串, atof字符串转浮点数
2007/05/30
类可以多重继承,如
class MultiDerived:public Base1,public Base2
若两个基类含有相同的方法或属性,在派生类中调用时必须指明调用方法的继承基类,否则会继承模糊编译错误,如:
MultiDerived M;
M.Base1::SetMember(10);
M.Base2::SetMember(20);
2007/05/18
删除CPtrList对象中节点示例:
for(POSITION p=list.GetTailPosition();p!=NULL;p=list.GetTailPosition())
{
delete list.GetAt(p); //释放节点占用的内存
list.RemoveTail(); //释放节点的引用指针,但不能释放节点占用的内存
}
list.RemoveAll();
因为RemoveTail、RemoveHead、RemoveAt都只是删除Reference而未释放引用的对象所占内存,故必须手动释放一遍。
CList.GetPrev(p)和GetNext(p)当p所指内存非法如已删除将返回0xfeeefeee,而并非预想的NULL,故若使用list.GetPrev(p)代替p=list.GetTailPosition()将可能使(p=0xfeeefeee)!=NULL循环继续执行而导致程序崩溃。
2007/03/06
alt+F8 格式化代码
使用CFile::modeCreate|CFile::modeNoTruncate打开文件可以保证文件不存在时创建且文件创建时不清空。打开后指针在文件头部,因此写数据时为避免覆盖已有数据,需要先SeekToEnd()将指针移到文件尾。
2007/01/11
CString类的FindOneOf(LPCTSTR lpszCharSet)函数返回参数lpszCharSet中的任一字符在CString对象中首次出现的位置,当lpszCharSet只有一个字符时,该函数同Find效果相同。
2007/01/16
CFile在写log时,flag要设为CFile::modeCreate|CFile::modeWrite,若只有modeCreate则Write数据时会报错:磁盘已满
===================================
非注明转载的文章和blog在未特殊声明情况下一般为本人原创或整理,版权 lonefox 所有,
欢迎转载,但请注明出处,保留作者和版权信息。
===================================