CATEGORY / Development

避免在 C++ 类结构中出现私有虚成员函数

最近在重构 C++ 代码时突然想起,如果一个基类的虚成员函数被设为 private,有没有意义?又是否合理?

当然,有其一定的意义,那就是不希望子类在其他地方调用父类的这个函数,包括在子类的实现中;如果需要这个功能,应该使用其 public 的接口去使用该功能。而子类可以提供自己的实现,以提供多态。但是,如果子类觉得需要,还可以把这个 private 的虚成员函数重定义成 protected(虽然这会让人迷惑),从而使子类的子类们调用它。

有同学可能会问,如果是一个 private 的纯虚成员函数(语法上当然合理),那语义合理么?嗯,我觉得这的确是个问题——也许是为了告诉写子类的其他同学,这个虚函数,我不希望你们在除了基类已有的接口里调用之外还来用——仅仅是一个道德约束?!

嗯,C++ 就是灵活得过头了,什么都让程序员自己去把控,可是别忘了,“太多的选择比没有选择糟糕得多”。所以,我决定,为了自己也为了别人不犯迷糊,避免使用 private 的虚函数,private 的成员函数仅包含当前类自己使用的函数。

BTW,类的成员变量正好相反,能设为 private 的尽量不要 protected 更不要public,否则后期维护,嗯嗯,就太痛苦了。


VS2010 中的 C++ 0x 新特性:Lambdas、auto 和 static_assert

转载自痴痴笑笑的博客,略有删改。

尽管 C++ 社区对 C++ 0x 很是追捧,但是各厂商对于新标准的支持并不热乎。盼星星盼月亮,微软作为 Windows 平台上最强势的 C++ 编译器厂商也终于在 Visual Studio 2010 中开始支持 C++ 0x 的特性。

Visual Studio 2010 中的 Visual C++ 编译器,即 VC10, 包含了 4 个 C++ 0x 的语言特性:lambda 表达式,自动类型推演(auto 关键字),静态断言(static_assert)和右值引用(rvalue reference)。
CONTINUE READING »


乱用 STL 是地狱

根据《Effective STL》条款21中的例子,建立一个比较类型为 less_equal 的 set 容器:

    set< int, less_equal<int> > s;

然后连续插入两个10:

    s.insert(10); // 10a
    s.insert(10); // 10b

会得到什么?

在debug下,可能会给出一个assert报比较符号不合法,第二次插入失败,但在release下,这个动作很可能是未定义的,而通常的结果是,set中存在了两个键值同为10的项,也就是说,set被悄声无息地变成了multiset!太可怕了!

所以,为正确的容器挑选正确的比较函数,很重要。用好 STL 其实并不容易,用错了不仅执行效率狂低,而且还可能出现这些难以想象的意外……


do...while(0) 的妙用

在 C++ 中,有三种类型的循环语句:for、while 和 do...while,但是在一般应用中作循环时,我们可能用 for 和 while 要多一些,do...while 相对不受重视。
但是,最近在读我们项目的代码时,却发现了 do...while 的一些十分聪明的用法,不是用来做循环,而是用作其他来提高代码的健壮性。

CONTINUE READING »


让 C++ 的 new 操作失败时返回空指针

C 中如果创建一个对象失败,就会返回空指针。但是对于 C++ 就不一样了,new 是不应返回空指针的,书上的推荐做法是在构造函数里抛异常。
当不想引入异常机制的时候,一般的做法是在构造器里啥都不做(最多做个变量初始化),加一个 Init() 函数来完成真正的初始化工作。
然而这样就使得每次创建一个对象,都要执行两步(new+init),总不是太方便,其实 C++ 的 new 操作符是带参的,可以通过“new(std::nothrow) CXxx”的方式让 new 失败时返回 null 指针,来标记失败(而不是抛出异常)。


严重避免在构造/析构过程中调用虚函数

之前只知道在 C++ 的构造器中,调用虚函数(非纯虚函数)不会出现多态的情况,却想当然认为既然析构器可以被声明为虚“函数”,那么析构器应该是能实现虚函数调用的的多态结果的。
事实证明,我又被蒙骗了!

构造器/析构器不会在调用虚函数时执行子类的重载实现,而且更危险的是当构造器/析构器“间接地”调用了虚函数(例如调用了一个非虚函数,但这个函数里调用了虚函数),不仅子类的重载实现不会被执行,而且还很难发现这种 bug。

所以,切记,切忌在构造器/析构器中直接或间接地调用任何虚函数!(单是在构造器/析构器中直接或间接地调用其他对象的虚函数并不受影响)


PBRT 学习:安装编译

去年在前公司看着 leader 用 PBRT 做基于 DX11/SM5.0 的 ray tracing 实验时,还懵懂得云里雾里。而我现在的 manager,在读研的时候就已经在研究 PBRT 了。我, out 了!最近由于工作的原因,终于开始着手学习 PBRT,而这玩意第一道关卡就是安装编译中的一堆问题,记录以备不时只需。

网上关于 PBRT 的资料基本都是 1.03 或更早的,而且基本都跳过了自动生成代码的预处理阶段。这次下载来的最新 pbrt-src-1.04.zip for Windows 虽然在其 release note 里说“a number of bugs and incompatabilities have been fixed”,但从我安装编译的经过来看,问题似乎更多了(斯坦福的大大们不应该这么粗心吧)。

首先把下载的文件解压到任意目录下,我这是“D:\Program Files\pbrt-1.04”,不过推荐还是放到分区根目录或者文件夹名不含空格的路径下,否则后面会多几个体力活。

PBRT 使用了 Bison 和 Flex 这两个工具来生成用于解析 pbrt 脚本文件的代码文件(这话有点绕哈),而这两个工具本是 Linux 下的,现在都有大大做了 Windows 版的移植(Bison for WindowsFlex for Windows)。分别把 Bison Binaries 中的 \bin 和 \share、Bison Dependencies 中的 \bin、Flex Binaries 中的 \bin 目录解压到任意目录下,我这是“D:\GnuWin32”。

这时 PBRT 还是不能编译的,原因是 1.04 中移除了对 OpenEXR 工具包的包含。OpenEXR 本身是三大 HDRI 格式之一,另外两种格式在以前我都处理过,而对 EXR 格式不熟,这里暂时也不做深究。OpenEXR 工具包可以在其官网下载(最新的 1.5.0 没有 VS2005 的预编译版本,我偷懒就直接下 openexr-1.4.0-vs2005.zip 了),也可以从 PBRT 1.03 zip 包中直接拿来用,然后整个解压出来,我这是“D:\Program Files\pbrt-1.04\openexr-1.4.0-vs2005”。这还没完,无论是官网还是 PBRT 1.03 里的 OpenEXR 工具包,在 \lib 文件夹下都缺少 zdll.lib 这个文件,去 zlib 首页下载 zlib compiled DLL zipfile,把压缩包中的 \lib 解压到 OpenEXR 所在文件夹下。

CONTINUE READING »


#ifdef 中的逻辑与或操作

原本用宏定义包起来的代码类似如下:

#ifndef A
// codes
#endif // A

现在要加入一个宏定义 B,实现类似这样的条件判断(显然实际上这样是不行的):

#ifndef A && ifdef B

其实应该这样:

#if (!defined A) && (defined B)
// codes
#endif // !A && B

这就修正了之前一直以为的“既生 #ifdef,何生 #if defined”的思维,其实还是有差别的


让 Visual Studio 2005 自动生成 Manifest

微软同学永远是个把简单问题复杂化的孩子,这不,当年为了在 Windows XP 中同时支持两套控件风格(新的 XP 风格和旧的 95/98 风格),“发明”了 .manifest 这么个玩意,使以前的老程序也能自动使用上新的控件风格。

然而在 VS 里,微软并不是总是默认帮我们自动生成这个破玩意儿。最早的办法就是手写一个 .manifest XML 文件,不过这个办法在 VS 2005 编译出来的程序里似乎并不起作用。当然,新方法总是随之而出的,而且很“简单”(绕了一大圈又回来了):

在 Project Properties 对话框的 Configuration Properties | Linker | Manifest File | Additional Manifest Dependencies 选项里,填入:

"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='6595b64144ccf1df' language='*'"

或者在程序里直接写下如下代码:

#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Test.Research.SampleAssembly' version='6.0.0.0' processorArchitecture='X86' publicKeyToken='0000000000000000' language='*'\"")

太阳又照常东升西落了 :)


Visual Studio 2008 无法进入修复/卸载界面的解决办法

最近需要在家办公,硬盘空间又不够了,只好卸了 VS2008 重装 VS2005,结果无论通过控制面板的卸载还是通过光盘的 autorun.exe,都在检查配置的时候弹出“A problem has been encountered while loading the setup components. Canceling setup.”的错误对话框,然后就自动退出了,连修复的机会都完全不给……

放狗在 MSDN 的论坛里搜到了这篇帖子里 George175 给出的解决办法,原来是 VS2008 的一个 patch 捣的乱,直接进控制面板,进入添加/删除程序(或卸载程序),左边选择查看/卸载更新,找到“Hot Fix for Visual Studio 2008”这个玩意儿,直接咔嚓掉。

然后,VS2008 就能正常卸载了。

另,微软的一位同学说安装 VS2008 SP1 也能解决,没有验证,应该不会有错。


« Newer Posts / Previous Posts »