为了能让编译速度快一点,明智之举是使用前置声明,而不是 #include 整个头文件。
那声明时候可以用前置声明,而什么时候必须 #include 头文件呢?简单的说:
- 当不需要用到类型的具体实现时,包括构造器、赋值运算符、成员函数等,只需要前置声明就可以了
- 当需要用到类型的以上方法时,就不得不 #include 整个头文件
类似 UltraEdit 里的“列模式”,按住 Alt 键再移动光标,就可以选择一块范围内的内容,而不必被束缚在只能一行接一行的选中方式了。
平时我都是用鼠标移到一行最左边的行号区去选中一行,然后执行复制或拖动等操作,其实,只要光标在某一行,直接按 Ctrl + X / Ctrl + C,就等于剪切/复制整行了,非常方便。
一直以来,当需要在多个文件中复制粘贴多个内容时,我都很笨地挨个 Ctrl + C / Ctrl + V,从来也懒得想是不是该搞个 multi-clipboard 工具来提高效率 -,-|||
其实,从 VS2003 开始,VS 就已经内置了多重剪贴板的功能,虽然只支持当前 VS 进程内多文件间的复制粘贴,这就是 Clipboard Ring。Clipboard Ring 采用 LIFO(后进先出)的方式组织,即最后被复制或粘贴的内容排在环的最前面,最大支持 10 块剪贴板。用法很简单,对需要复制的多个内容块按 Ctrl + C,然后到需要粘贴的地方按 Ctrl + Shift + V,选择需要粘贴的内容就 Ok 了。每个 VS 版本的 Clipboard Ring 操作略有不同,在此不赘述了。
待续……
CTreeCtrl 的 GetNextItem 成员函数很诡异,nCode 设为 TVGN_NEXT | TVGN_CHILD 会一直返回传进去的 hItem 值,而不是返回下一个兄弟 item “或”第一个 child item。
所以,只好自己写遍历函数,没有采用递归的做法,用了一个 STL List 容器来保存下一个兄弟 item 和第一个 child item,遍历返回的依据是 item 的 lParam 值等于给定的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | HTREEITEM CModelNodeTreePane::_GetTreeItemByID(const unsigned int uiItemID) { HTREEITEM hCurrItem = m_kModelNodeTreeCtrl.GetRootItem(), hItem; std::list kItemList; kItemList.push_back(hCurrItem); while (kItemList.size() > 0) { hCurrItem = kItemList.front(); kItemList.pop_front(); if ((unsigned int)m_kModelNodeTreeCtrl.GetItemData(hCurrItem) == uiItemID) { return hCurrItem; } if ((hItem = m_kModelNodeTreeCtrl.GetChildItem(hCurrItem)) != NULL) { kItemList.push_back(hItem); } if ((hItem = m_kModelNodeTreeCtrl.GetNextSiblingItem(hCurrItem)) != NULL) { kItemList.push_back(hItem); } } return NULL; } |
由于程序里的 CTreeCtrl 控件实例是通过 CTreeCtr::Create() 来创建的,无法通过 VS 的 Properties 面板里的 Control Events 工具来生成消息映射函数,但控件又需要响应鼠标点击事件,这时最简单的办法就是重载 CTreeCtr 实例的 owner 的 OnNotify() 成员虚函数(这个 owner 也必然是 CWnd 的子类):
protected: virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | BOOL CTreePane::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) { NMHDR* pNMHDR = (NMHDR*)lParam; ASSERT(pNMHDR != NULL); switch (pNMHDR->code) { case TVN_SELCHANGED: _OnTreeCtrlSelChanged(wParam, lParam, pResult); break; default: break; } return CWnd::OnNotify(wParam, lParam, pResult); } |
Internet Explorer 8 正式版会导致 Visual Studio 2005 / 2008 里的部分 VC++ 向导出错,包括:
VC++ 团队给出了解决方案:
然后重启 VS 即可。
注意:VS 2005 必须装上 SP1。
想深究这个问题原因,可以参看原文。
这段时间要搞角色换装系统的改进,参考魔兽世界的换装系统机制,便先拿了 WoW Model Viewer 的代码来参考。
先拷来一个 0.48b 版本的代码,按照这里说的做后编译是通过了,但运行总报错,跟了一下没找到问题,索性去下了 0.5.08 。该版本使用 wxWidgets 2.8.0、CxImage 5.99c、GLEW 1.3.3,其中 wxWidgets 2.8.0 需要自行下载、编译。
然后打开 wowmodelview.sln,打开工程属性,修改 C++ | Additional Include Directories、Linker | Additional Library Directories 中关于 wxWidgets 的路径,然后编译,这时可能会报一些 build error,基本都是类型没有显式强转的问题,改掉即可。
编译完成后,需要修改配置文件 Config.ini,把 [Locale] 下的“Path=”和“MPQFiles=”后的路径都改为 .mpq 文件所在文件夹根目录,就可以运行了。
我前段时间去面试时的一道题目,问题如下:
有一个脚本文件,每行有一句指令或空行,指令格式:
Command[,Param[,Value]]其中Parameter 和 Value 非必须。设计一套解析指令的类,高效且易于扩展(尽可能降低代码内部耦合性)。
当时虽然都想到了,不过满脑混沌,没有完整明白地表达出来。本来想去公司再看看代码是怎么实现的,昨天在网上闲逛的时候忽然看到了这篇笔记,那就顺便也整理了下自己的思路,结合实际温故理论。
假设有“移动(Move)”、“攻击(Attack)”等几个指令;建立一个工厂类,并将所有指令类预先注册到工厂中,由工厂调用每个指令类的静态成员函数 CreateInstance() 来实现指令类实例的创建:
这是我拿到公司 offer 时美国老大给我的面试题,对于当时我这种文盲来说,还是杀死了不少脑细胞。最近闲来无事(嗯。。。被危机了),又拿出来琢磨了一下各算法。
设一在在 2D 空间中的三角形 △ABC ,三个顶点向量 A(ax, ay)、B(bx, by)、C(cx, cy),三条有向边 AB、BC、CA,有一点 P(px, py)。
原理:
沿 △ABC 各有向边按一定方向走(顺时针或逆时针),判断点 P 是否在该边的某侧(右侧或左侧),若点 P 在三条边的同侧,则点 P 在 △ABC 内。
实现:
分别计算向量 AB、BC、CA 与向量 AP、BP、CP 的向量积(叉乘),若三个结果均同号(正或负,为零表示 P 在边上),则可得点 P 在 △ABC 内。其中AB = B - A,AB×AP = AB.x*AP.y - AB.y*AP.x。
该算法只需要做 3 次叉乘(6 次普通数值乘法),效率高,且没有浮点误差。
这是我当时面试想的算法,Azure 等人也用的类似算法。
原理:
若点 P 在 △ABC 内,则 △ABP、△BCP、△CAP 的面积之和应等于 △ABC 的面积。
实现:
利用两个向量叉积的几何意义为该两个向量所围三角形面积的 2 倍,分别计算 AB×BP、BC×CP、CA×AP、AB×BC,若 |AB×BP| + |BC×CP| + |CA×AP| = |AB×BC|,则得点 P 在 △ABC 内。
这个算法用得比较普遍,需要做 4 次叉乘(8 次普通数值乘法),效率和叉乘法差不多,同时避免了用海伦公式计算面积的低效和精度问题(数值除法和开方运算)。
我昨天想的一个算法有点类似这篇文章中的方法 3,比它简单一点,但同样需要对向量做归一化处理,效率不高,故放弃了。另外的算法还包括划线交点法、解方程组法、复数法等,但计算量都较大,不再赘述。
最近碰到用十六进制数表示浮点小数的问题,本科没学好,现在是补习时间。
FP32(单精度浮点数)
S EEEEEEEE FFFFFFFFFFFFFFFFFFFFFFF 31 30 23 22 0
v = (-1)s × 2e-127 × 1.f
十进制浮点小数转 IEEE 754 格式的方法,以 −118.625 为例: