2008年6月15日星期日

美国和中国最大的不同

来美国也快一年了,就说说我在不同时期感受到中国和美国最大的不同吧。当然,题目有些误导之嫌,毕竟中国和美国都那么大,我也没有资格去全面地比较,就只说我作为一个来美国读博的本科毕业生,在成都、广州和Santa Cruz和感受。

刚来:1) 所有人都在说英文;2) 美国人很好客,很直接。
第一条不用解释,如果当初是郑和而不是哥伦布发现这里的话,可能现在有所不同。在公交车上所有人说的话,你能听懂一点点,但大概意思就不知道了。总的说来还是比在广州好,至少我的英语水平比我的粤语水平高。
第二条,感觉美国确实是一个多民族混居的国家,他们对外国人的友好比我想象的要多。说话直接也和传说中的一样,一般来说都没什么小心眼儿。中国的那一套拐弯抹角在这里最好不要用。

一个月后:1) 美国人的饮食习惯、结构和中国人不一样。2) 在美国,钞票很少用,信用卡居多。3) 感恩节购物狂潮。
第一条,美国人基本上不像中国人那样炒炸煎煮食物,更多的是生吃蔬菜,面包,肉片什么的。很多国内的菜这边见不着,比如冬瓜,白萝卜,鳝鱼这些。很多这边的菜国内也没见过,比如Artichoke,各式各样的蘑菇。
第二条,钱包里基本上不会放超过50美元的现金,相反,各种卡则一个都不能少。基本上所有的店铺都接受信用卡刷卡(现金也接受),方便,快捷。另一个好处是安全。即使信用卡被盗,银行也会保证你不会有任何损失。
第三条,感恩节那几天买了很多东西啊!刚来这儿本来也缺很多东西,加上打折又那么厉害。美国这儿网上购物很方便,也很便宜,没听说过像国内那种骗钱的网站。法律完善的结果吧。

两个月后:1) 和广州、成都相比,美国这儿的饭馆太少啦!2) 美国教育体系更完善,强度更高。3) 美国自然保护做的很好。
第一条,感慨了美国人的饮食习惯,就轮到自己受罪了。一般自己做饭,买现成食物太贵。本来能做的菜就不多,吃多了就腻了。想去下下馆子改善伙食,可没在国内那么容易。一是少,没汽车的话那距离足够让人打消念头了(去吃个饭还要坐公交车,还要坐车回来,唉……),二是口味也不合适。美国饭馆也不外乎就是沙拉,牛排什么的,墨西哥饭馆就不说了,吃过两次Taco,发誓今生再也不吃那玩意儿了,中国餐馆听说做得还没自己好吃,变化很大,算了。可能大城市会好些。
第二条,在美国,学习是很自由的,可以很努力,也可以很放松,完全看个人。做TA那段时间接触的本科生,感觉虽然刚开始也是什么也不懂,但学习能力很强,一个学期下来他们是真正自己学到了很多的。课程方面他们很强调自主独立性和实际动手能力。当然也有抄别人作业、考试作弊的学生,但这并不影响那些优秀的学生学习,毕竟那也只是少数,自己对自己负责就行了。
另外最大的感触是,这边的学习非常强调学生自己展示自己。我第一个学期的Advanced Operating Systems,基本上就是班里10个学生每个人读相同的4、50篇论文,然后自己争取在每堂课上用45分钟时间用自己的话来阐述自己对文章的理解。平均下来,每个人分到4次左右演讲。这对于我这个刚来美国连英语都成问题学生来说是极大的挑战。首先每个星期要读完3、4篇15到20页的英文论文就要花很多时间,加上还有别的课,压力就很大。如果轮到自己演讲,还要理解自己的那篇论文,做出PowerPoint,又是很多时间。其次,演讲时候的口语表达也是难点。中国学生学英语的最大问题也就是口语了,因此刚来美国时能听懂别人在说什么,但就是不知道怎么表达自己的意思。现在要说的还是专业性很强的东西,就更难了。另外这个课还要做Project,因此一学期下来最大的感受就是,学习太累了。后来发现并不是单单这个课很累,所有的课都累,只是慢慢地逐渐适应了这种学习方式,也就好了。本科生在这方面的要求虽然没那么高,但也是有的。
第三条,眼见为实。就说几个例子,Santa Cruz这儿有一条小河,清澈见底,野鸭、海鸥很多,相比一下成都的府南河,广州的珠江,唉……;Santa Cruz很有名的是她的Wharf,一条一公里长伸到海里的木桥(有兴趣可以Google Map),Wharf下面海里海狮(Sea Lion)成群。这要在中国,为它们祈祷吧;学校里红杉树很多,俨然就一个森林里的建筑群。能让人类活动和自然生态相处地如此和谐,在中国我看很难。

四个月后:美国的税收制度很完善,可能太过完善了。
在美国报过税的人都知道。

六个月后:美国人很尊重每个个人的观点意见,崇尚自由。
这是我很欣赏美国的地方。无论你的观点他们是否同意,无论他们时候和你争论,他们都会很尊重你自己的观点,对你说"Cool!"。美国崇尚自由的特点很明显的体现出来。你可以完全按你自己的方式说话,饮食,生活,只要不要严重影响别人。因此在美国社会里,你可以听到各种各样的声音,各种各样不同的观点,所有的观点无论对错,无论激进与否,都可以存在,这才是民主的体现。希望中国有一天也可以变成这样。

一年后:美国人办事效率也不总是很低的。
美国人办事效率低应该是很有名的了,比如去银行,DMV,一个人有时候可以办10分钟,结果最后只是取个钱,拍个照。最近一个月,我注意到三次修路的工程,效率各不相同。第一个是市的主干道(Bay St),总体用了一个星期,主要就四天施工时间,效率很不错。第二个是学校的主干道(Glenn Coolidge Dr),总体两个星期,主要一个星期施工,而且用了很多机械,卡车,长度和第一个差不多。第三个是一个小街区的干道(Tosca Ter),已经一个多星期了,刚刚才把道路挖开,完全没有进展的样子。每天都可以看到3个人,其中一个专门望风(比如拿个举着SLOW的牌子),另外两个站在路中间,好像什么都没干的样子。从施工人数来看,第一个和第二个相当,第三个要少得多,这说明并不是没有可用的人,而是优先级不同的原因。结论是,如果有必要,美国人的效率完全是可以快起来。往往可能觉得没那个必要,慢就慢些,美国人也习惯了慢慢来,所以效率就低了。

就说这么多,以后再慢慢添加。

2007年9月28日星期五

第一节课

今天刚上完在美国的第一节课,Programming Languages。主讲的 Prof. Flanagan 是一个很年轻的教授,语速很快,我觉得我最多听懂了六成的内容。课的内容并不是对某几个语言进行解释剖析,而是概观地对编程语言的历史,特点,要求等等进行介绍和讨论。一个很大的不同是,当每个同学介绍自己喜欢的语言时,很多人更倾向于Perl, Python, Ruby这些脚本语言,这些在国内基本上是十分生僻的。Prof. Flanagan则很喜欢Java。

我这学期的TA也要求会一点Perl, 所以还是要花功夫在这些原先不熟悉的脚本语言上。

研究生的生活比想象的要累啊。

2007年9月19日星期三

The first 4 days in USA

I'm using the computer in the Library of UCSC to write down this article. Since there is no Chinese Input Method, I can just only use English. Sorry.

I was a terrible journey flying to America. Due to some "Mechanic Problem", the flight from Chengdu to Beijing was delayed, for about 3 hours. Therefore, I did not catch the original flight from Beijing to San Francisco. After 5 hours terrible waiting, I finally got on an airplane flying to Los Angeles. 11 hours on plane, no deep sleep, I had been very tired. Entering the Custom and Border Protection was straight. 1 hour later, I flew from Los Angeles to San Francisco. When I got there, it was 10:00 pm, PST. Fortunately, Peggy Pollard, a member of ISI(International Student Inc.) came to the airport and pickup to Santa Cruz. It was very kind of her!

I was living with four Chinese exchange students temporarily. We got along with each other very friendly. They told me lots of things here, about housing, banking, campus, calling plan, yard-sale, etc.. Yesterday, I settled down in a house near the beach of Santa Cruz, which was a wonderful place to live, full furniture, $560 rental per month, plus month to month payment. I do not hope better.

Santa Cruz is a small town, with about 56000 population, mediterranean climate, friendly people. There is no crowd of people, and all town is quiet. Santa Cruz means "Holy Cross", which is famous for the beach and surfing here. Everybody should like it. By the way, bus transportation is powerful in Santa Cruz.

The campus is wonderful, too, since it is sitting on a hill and in a forest. More properly, I should say, UCSC is just a part of the Mt. Santa Cruz, because the natural environment here is well preserved. You can see deers eating grass, and squirrels are fighting for nuts. Inside of the forest, the temperature is very low, but the air is even more fresh. I can say, I like here.

There can be lots of things to tell, but I must stop here. I think my oral English is growing better and better everyday.

:)

2007年9月2日星期日

最近的情况

最近逐渐熟悉了Colemak键位,打字速度开始恢复了。确实,世上无难事,只怕有心人。

关于RecycleTorrent,我完成了应有的基本功能,已经把代码传到了SourceForge。SourceForge上RecycleTorrent项目的地址是http://sourceforge.net/projects/recycletorrent/。同时,编译后的程序可以在我的Windows Live SkyDrive上下载(运行需要安装最新的Visual C++ 2005 Redistributable Package)。对BitTorrent感兴趣的开发者可以试试。

另外,最近打算将RecycleTorrent扩展成P2P下载平台。具体细节我还在考虑。

2007年8月23日星期四

尝试Colemak布局



Colemak(http://colemak.com/)键盘布局是我在比较Dvorak键盘布局的效率时认识的。Colemak给我的第一印象是,它跟QWERTY很像,ZXCVBQW这些键的位置都没有变。在Colemak网站的FAQ(http://colemak.com/FAQ)上,发明者Shai Coleman列举的Colemak优于其他键盘布局地方有(括号内是我的解释):


  • Colemak的用户群正在增加。(有助于不断完善Colemak,开发相应软件。)

  • Colemak的设计初衷之一就是易学,很容易从QWERTY转换过来。(Colemak指改变了17个按键,而Dvorak改变了33个按键)

  • Colemak保持了Ctrl+Z/X/C/V四个快捷键的位置(请参见我的文章《解决Dvorak键盘布局快捷键的问题》)

  • Colemak对小指的负担不高。(Dvorak把L放在右上角。L键是一个常用键,因此对右手小指要求较高)

  • Colemak键盘布局的设计很稳定。(不会经常变化,要求用户重新熟悉)

  • Colemak可以在多种操作系统上使用。(Windows, Mac, Linux/Unix)

  • Colemak有相应的打字练习。(http://colemak.com/Learn)


对于在Windows下使用中文输入法的用户来说,安装Colemak布局的最好方式是注册表重映射(Registry remapping)。注册表重映射是在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout键下建立一个名为Scancode Map的二进制键值,用于存放新键盘布局的键盘扫描码(Scan code)。启动系统时,Windows读取修改后扫描码,这样,整个键盘就被重映射了。如果想改回QWERTY布局,只需要删除键值,重启即可。

为什么是最好方式呢?因为一般输入法都有自己的键盘映射模块,会自己判断扫描码。注册表重映射是很低层的修改,新键位对输入法同样有效。

Colemak的注册表重映射实现在这里下载:http://colemak.com/pub/windows/Kmapper-1.0.zip。其他实现方式在这里下载:http:http://colemak.com/Download。

用Colemak打了这两篇文章后,感觉最不舒服的是J键。虽然J在英文里是极罕见字母,在拼音里确是常用字母。但愿习惯后会好些。

解决Dvorak键盘布局快捷键的问题

虽然Dvorak键盘布局比QWERTY的排列更合理,但对于已经习惯QWERTY键盘的人来说,迁移的难度是很大的。对于惯用右手握鼠标的人来说,其中之一便是左手的那些热键,Ctrl+Z, Ctrl+X, Ctrl+C, Ctrl+V, 等等。因为现在的ZXCV都在键盘偏左的位置,所以不得不用右边的Ctrl键;另外,ZXCV等键相隔都很远,按起来很不舒服。

有没有办法修改Windows的全局热键呢?当然不行,我们没有Windows的代码。

能否使用重映射(Remapping)按键将ZXCV等键映射到原来的位置呢(这种方法很常见,很多日本同人格斗游戏的按键都可以通过软件修改到WASD来)?不行,因为这样就破坏了Dvorak键盘布局。

我们要找的是这样的工具,它能全局地拦截按键,并对指定的按键进行替换。替换的要求不只是单独的按键,同时要是按键序列。替换后的按键同样不只是单独的按键,同时要是可自定义的按键序列。

我尝试了很多软件,都无法满足以上的所有要求。昨天下午,无意间在VeryCD的一篇帖子里找到一个名叫Key Transformation(http://www.softboy.net/key/)的软件,试用后发现它满足所有要求。不过这是一个收费软件($44.95!)。要知道,别人一套虚拟机(Parallels Workstation)也才$49.99啊,怎么说,虚拟机的含金量也要高得多吧。放弃……

终于,在RandyRants找到了一篇文章介绍AutoHotKey(http://www.autohotkey.com/)。这是一个开源软件,免费。它能读取脚本文件,按宏的定义来替换按键。由于AutoHotKey支持的宏命令非常丰富,所以它完全能够胜任我们的要求。

比如,我们创建一个脚本文件test.ahk,输入

^j:: SendInput ^c

运行脚本后,按下Ctrl+J就相当于按下了Ctrl+C,而Dvorak的J键就在QWERTY的C键的位置。

当然,我们完全可以用AutoHotKey来模拟出一整套Dvorak键盘布局。事实上,在AutoHotKey的论坛上已经有人写出了脚本(http://www.autohotkey.com/forum/topic4473.html)。

另外,如果有兴趣的话,可以到这里(http://www.siteuri.ro/dvorak/)看看。这里有一个程序,你输入了一段文字后,它可以输出用各种不同键盘布局输入的效率比较。48小时之内允许测试5次。注意,最后一个键盘布局是Colemak,我正在熟悉它。关于Colemak键盘布局,我在下一篇文章中详细介绍。

不过,用新键盘来打出这么多字真是很累啊。万事开头难。

2007年8月20日星期一

RecycleTorrent 能够正常工作了!

经过近半年的努力,现在终于把一个有界面、有逻辑的基本BitTorrent客户端做出来了!主要还是用了Qt的框架,在Visual Studio 2005 SP1上编译。中间遇到很多问题,在解决问题的过程中也学到了不少,得到很多乐趣,这也是激励我在计算机这个行业中不断前进的动力了。

当然,目前连一个Alpha都还说不上,因为功能很不完全。不过既然已经走上正规,后面的工作主要就是体力活了:)

放上几张截图:


初始状态


尝试连接中


和BitComet对传数据


断开连接后

------------------------------------------------------------

当我把程序复制到一个干净的Windows XP SP2虚拟机里时,居然报错,截图如下:



Dependency Walker出错如下:



Side-by-Side?没怎么听说过啊?其实就是%systemroot%下面那个WinSxS文件夹里面装的文件。那些动态链接库按版本存放在WinSxS里。生成程序的时候,VS会创建.manifest文件,该文件用于保存目标文件的外部依赖的库,同时记录库的版本。当库文件未找到或者版本不符时都会提示程序无法运行。因为虚拟机里当然没有安装VS2005 SP1对应的CRT库,所以报错。下载Mircosoft网站上的Visual C++ Redistributable并不能解决问题,因为Microsoft目前还没有更新到SP1版本。当我复制[Visual Studio 2005 安装目录]\SDK\v2.0\BootStrapper\Packages\vcredist_x86\vcredist_x86.exe到虚拟机并安装后,就没有问题了。Microsoft的东西还真是挺麻烦的。(主要参考了这篇文章:Side-by-side screwup)

2007年7月30日星期一

在维基百科上发表了我的第一篇条目——瓦尔哈

源起我前两天在听瓦尔哈演奏的巴赫管风琴全集。应为是暑假回家来第一次听,确实很受感动,突然想去看看维基上关于瓦尔哈的条目是怎么描述他的。谁知中文维基上居然没有瓦尔哈的条目,英文的也写得很简略(维基上演奏家们的条目都相对较少,虽然他们可写的东西并不少)。

我想,听了瓦尔哈那么多的演奏,都没有为他做点什么,正好可以借这个机会报答一下。虽然我手上关于瓦尔哈的资料并不多,但网络本身就可以提供大量信息。于是花了两三天时间,把网上搜集到的资料收集整理后翻译成中文,加上图片,就成为了一个条目了。

维基是自由的网络百科全书,希望任何爱好音乐的朋友都来参与。如果我写的有什么不对的地方,请大家修改。

条目地址为:http://zh.wikipedia.org/wiki/%E8%B5%AB%E5%B0%94%E7%A9%86%E7%89%B9%C2%B7%E7%93%A6%E5%B0%94%E5%93%88

在国内由GFW无法直接连接维基百科。但因为Blogspot也是被封站点,所以既然您能看到这篇文章,那您可以使用相同的办法办法访问维基百科(条目应该没有敏感字词)。

2007年7月26日星期四

写了一个Firefox的扩展

实在受不了GFW的横行霸道。凭什么要把Wikipedia、Google Cache这些站点封了呢?现在就连上这个Blog都得用代理了,哎……于是,我在ErrorZilla Mod的基础上加上了对失败地址使用Web代理进行访问的功能。

插件名叫ErrorZilla Plus。下载安装后,每次遇到无法打开的地址,一个新的失败页面就显示出来。和ErrorZilla Mod不同的是,现在多了一个"Proxify"的按钮,其下增加了一个列表框。列表框里保存了几个Web代理的名字。用户可以在这几个代理中选择一个,用它对失败的页面进行访问。这样,每次打开维基中文出错后,只需要点一下Proxify就可以访问了。

目前初版是0.3版。在这个版本里,我是把代理列表直接保存在netError.xhtml里的,因为我实在找不到如何在Firefox里读取外部文件的方法,即使是XML也不行。还要请高手指点一下。

如果要修改代理的列表,请打开ErrorZilla Plus安装的目录(<当前profile目录>/extensions/{03651b2d-eb7d-4be7-af1b-dc0cd162dd54}),找到Content文件夹下的netError.xhtml。在该文件中部有一段标签的内容。代理列表在这里以XML的格式保存。name节点保存代理站的名字,website节点保存站点的地址,address保存查询页面的相对地址。更改了列表后请重新启动Firefox。

ErrorZilla Plus的下载地址是https://addons.mozilla.org/en-US/firefox/addon/5398,目前还在沙盒(Sandbox)中。

--------------------

又查了一些资料。Mozilla在扩展的Javascript里有执行权限的限制。向about:这样的地址的权限较低,因此无法调用外部文件。我试了一下XPCOM组件,直接打开about:neterror时,执行Components.class会提示“Uncaught exception: Permission denied to get property UnnamedClass.class”,而通过Chrome(打开chrome://errorzillaplus/content/neterror.xhtml)则没有问题。我想这个问题暂时没法解决,除非Mozilla修改它的权限策略。

2007年7月19日星期四

Singleton (单件) 设计模式

[2007.04.01]

最近在苏州一家计算机公司工作。因为大量用到了Singleton模式,而原来自己实现的Singleton模式存在内存泄漏的问题,所以花了点时间研究如何更好地实现Singleton模式。

我原来实现的Singleton模式是这样的:

(Singleton1.h)

class Singleton
{
public:
static Singleton* Instance()
{
if (_instance == 0)
_instance = new Singleton;

return _instance;
}

private:
Singleton() { _testPtr = new int; }
~Singleton() { delete _testPtr; }
static Singleton* _instance;

int* _testPtr;
};


(Singleton1.cpp)

Singleton* Singleton::_instance = 0;


很明显,Singleton::_instance 只是一个指针,在程序结束的时候并不会被自动析构,因此Singleton::~Singleton() 也不会被调用,完全是一个空壳。为了使Singleton类被自动析构,一个最直接的办法就是把Singleton::_instance改成类的实例而非指针,这样静态变量_instance就会在程序结束的时候自动被析构,再设法让_instance中的析构函数调用Singleton类的析构函数,就可以解决内存泄漏的问题了。

这里有三种解决方案:
1. _instance是一个和Singleton类不相关的类(假设为SingletonDestroyer)的实例;2. _instance是Singleton类的父类的实例;3. _instance是Singleton类自己的实例。

第一种解决方案首先被排除,因为如何让SingletonDestroyer访问Singleton类的析构函数是一个问题。Singleton类可以是任何不同的类,有不同的接口,无法统一地被SingletonDestroyer处理。当然,可以让所有的Singleton类继承于一个基类,使它们具有相同的接口,再在SingletonDestroyer中保留一个此基类的指针,在SingletonDestroyer::~SingletonDestroyer()中调用基类指针的析构函数( _singleton->~Singleton(); ),但这样其实已经退化成第二种解决方案了,所以第一种解决方案被排除。

让我们来看看第二种解决方案的实现。

(Singleton2.h)

class Singleton
{
public:
Singleton() { _singleton = 0; }
~Singleton()
{
if (_singleton != 0)
{
_singleton->Destroy();
delete _singleton;
}
}

Singleton* _singleton;

protected:
virtual void Destroy() {}
};

class Sub : public Singleton
{
public:
static Sub* Instance()
{
if (_instance._singleton == 0)
_instance._singleton = new Sub;

return (Sub*)_instance._singleton;
}

private:
Sub() { _testPtr = new int; }
void Destroy() { delete _testPtr; }
static Singleton _instance;

int* _testPtr;
};


(Singleton2.cpp)

Singleton Sub::_instance = Singleton();


Sub是实际的单件类,所有Sub类都继承于Singleton类。Sub::_instance是一个Singleton类的对象,在程序结束时会被自动析构,调用Singleton::~Singleton()。Singleton类的Destroy()是提供给子类销毁自己的成员数据的,会在Singleton::~Singleton()中调用。如果子类不覆盖Destroy(),则不执行任何程序。

这个解决方案在非MFC的单线程程序中可以正常工作,但是在多线程的MFC程序中有问题(运行到afxmem.cpp的某行会出错),其他情况我没有测试。在我这里这个解决方案也被否决了。

第三种解决方案:

(singleton3.h)

class Singleton
{
public:
static Singleton* Instance() { return &_instance; }
void Setup(int intValue) { *_testPtr = intValue; }

private:
Singleton() { _testPtr = new int; }
~Singleton() { delete _testPtr; }
static Singleton _instance;

int* _testPtr;
};


(singleton3.cpp)

Singleton Singleton::_instance = Singleton();


还是第三种方案最简单。Singleton::_instance是自己类的实例,由于是静态成员,所以可以存在。程序结束时,自动调用自己类的析构函数。在MFC和非MFC、单线程和多线程中都没有问题,可以参考。
4.23更新:如果Singleton类是继承于一个父类BaseClass,那么它的_instance变量的类型和实例化都应该不变,而不是像指针那样,BaseClass* _instance; _instance = new Singleton;

另外还有一个第三种方法的变种,就是使用智能指针std::auto_ptr,代码如下:

(Singleton4.h)

#include <memory>

class Singleton
{
public:
static Singleton* Instance() { return _instance.get(); }
~Singleton() { delete _testPtr; }
void Setup(int intValue) { *_testPtr = intValue; }

private:
Singleton() { _testPtr = new int; }
static auto_ptr<singleton> _instance;

int* _testPtr;
};

(Singleton4.cpp)

auto_ptr<singleton> Singleton::_instance(new Singleton);


[2007.07.19 更新]

其实既然Singleton的生存周期贯穿整个程序,那么必然只有在程序结束的时候才会析构Singleton类。既然程序都结束了,操作系统也会自动回收所有相关内存,那么Singleton类的析构就显得多余了。

因此,又写了一个Singleton的模板类,更方便一点了:

(Singleton5.h)

template <typename T>
class Singleton
{
static T* _instance;

Singleton() {};

public:
static T* Instance()
{
if (_instance == NULL)
_instance = new T;

return _instance;
}
};

(Singleton5.cpp)

template <typename T>
T* Singleton<T>::_instance = NULL;

注意,Singleton的相关实现也要放到头文件里。使用时,所有类继承于Singleton,并传入类自己作为模板参数。如果子类希望有private的构造函数,则还需要让自己和Singleton类成为友元,因为Singleton里有new T,会访问子类的构造函数,而并没有什么修饰符可以指定只允许父类访问,而不许其他对象访问。

如:

class Sub : public Singleton<Sub>
{
friend class Singleton<Sub>;
Sub();

public:
int testFunc() { return 0; }
};

main()
{
Sub::Instance()->testFunc();
}

总结一下。某些类一个程序执行期间只需要存在一个副本。通常这种类仅仅提供某些功能,不存储任何数据,或者仅存储程序的全局数据。对于前者,只需要将类的所有函数设为静态函数即可。对于后者,则使用单件模式。一个类由普通类转换成单件类不需要做任何修改,只需要添加_instance成员变量和Instance()成员函数。