Kindle Touch入手

广告版99刀,提前发货所以提前入手。简评:

  1. 价格实惠;小,轻,可以直接放大衣兜里;
  2. 广告版不注册的话没有广告;
  3. txt中文默认字体巨挫,巨挫无比。相比较而言日文显示超完美,为什么?
  4. 貌似没看图程序了,可能是我打开方式不正确?反正用之前的方法添加图片后没显示;
  5. 翻页速度比K3又有提升,但看pdf仍然是全屏刷新;
  6. 浏览器效果依然蛋疼;
  7. 触屏查词不错,整体来说交互要方便许多。
  8. 哦对,默认pack不带充电插头哦,要单买。

尺寸对比。

Read more >>>

地坛冬季书市归来

这次的冬季书市感觉比春季和去年几次的规模都大,而且最大特点就是卖东西的摊位类别更杂。之前觉得看到卖茶叶就是极限,今天去竟然还有北京原来有名的义利巧克力在促销。

进门之后第一印象,还是人多。虽然我不喜欢凑热闹,买书都找安静地方,但每次乱哄哄的书市却并不让人烦。而且依然是男女老少各个年龄都有、背包手提小拖车齐上阵,甚至还见到了超市那种推车,明显是朝着一折的《二十四史》这类书籍去的。

Read more >>>

《深度探索C++对象模型》学习笔记(1-4章)

今年静下心来重读了侯捷老师译本的Lippman大神作品《Inside the C++ Object Model》,记录下学习过程中的疑问和心得有助于以后……面试。不是开玩笑,这本书里面随便找一段出来都可以当作C++面试题,学透彻了的话,无论是面试别人或者被人面试都是相当犀利的武器。

第1章 对象

对象

OOP的成本

  • 实际上相对于struct来讲,class只是程序员友好的手段
  • 单纯使用class以及继承,内存成本并不会增加,成员函数也会由编译器进行转换(4.1函数成员:调用)
  • 真正需要额外成本的是virtual特性。

对象布局方式:简单对象模型

  • 思想:尽量降低实现的复杂度
  • 每个对象中的项目都是一个slot,按照顺序排列
  • 数据成员本身并不放置在对象中,只保存指针,避免变长对象出现
  • 没有用于实际产品中(但成为指向成员的指针的灵感来源)

对象布局方式:表格驱动的对象模型

  • 对象保存两个指针,一个指向拥有所有数据成员指针的表格,一个指向拥有所有成员函数指针的表格
  • 也没用于实际产品中(但指向函数指针表格的指针,演化为vptr)

对象布局方式:C++对象模型

  • 演化自简单对象模型
  • 非静态成员存储于类内。静态的则都位于之外。
  • vptr和vtbl的概念。用于支持RTTI的type_info位于vtble第一个slot内

继承的情况

  • 简单模型:子类描述基类的slot保存基类指针,优点是父类的修改不会影响子类
  • 另一模型:保存一个基类表格,子类拥有一个bptr指向之。表中的slot再指向具体的基类

差异

关键字差异

  • class和struct的思考:为了兼容C而多做了很多工作
  • struct表现数据集合体,而class为OOP而生
  • class的多个section不能保证成员在内存中的顺序和声明的一样
  • struct目前的作用,抽取class的一部分作为参数传给C函数

对象差异

  • 三种programming paradigms
    1. procedural model,C语言的函数调用
    2. ADT model,隐含的调用,例如等号运算符
    3. object-oriented model,面向对象特性
  • 多态的实现需要由指针或引用来实现,但C++中的指针和引用并非多态的必然结果
  • 支持多态的方法
  • 指针的转换(基类子类)
  • 虚函数调用
  • dynamic_cast或者typeid运算符

指针和多态

  • void*虽然可以指向某地址,但并不清楚具体类型,也不能通过它操作对象
  • D继承自B,D的大小为B的子对象加上D特有的部分
  • D*和B*的指针对象虽然都指向同一个开始地址(B的开头),但它们涵盖的范围不同
  • 指针在编译期会决定固定的可用接口(public)以及接口对应的访问范围,这类信息都在链接(link)中,它位于vptr和其指向的vtbl之间
  • 编译器在构造和赋值时候会决定vptr的值。如果对象含有多于1个的vptr,那么就不用基类指针进行覆盖(5.4构析拷贝:拷贝赋值)

Read more >>>

《ギャラリーフェイク》(赝品画廊)

最近虽然PSV热销得紧,但考虑了一下还是没有预定,因为只要有AVG在,PSP还能再战五百年。能否将手头正在攻略中的游戏打完暂且不提,还有过去已经发布的AVG,再加上现在AVG不说质量如何先把文字量和游戏时间提上去了,以后很长一段时间都可以用来回顾漏过的好游戏。

近几天在玩的《ギャラリーフェイク》(赝品画廊)是漫画、动画和游戏的三栖作品,原作由細野不二彦在小学馆的《Big Comic Spirits》上连载,并且得过小学馆漫画大赏(顺带一提《墨攻》原作、《20世纪少年》、《深夜食堂》和《少年犯之七人》都曾拿过此奖)。在连载终结的05年被连续改编成动画和游戏,而且改编作基本都是踩着前作肩膀出现,这种规划显然是要一口气扩大作品的影响。漫画版第一眼看上去还以为是80年代的作品,有作画风格的因素,也有整体色彩给人的第一印象,但作画本社质量不错,总体来说可算差强人意,又有三位大牌(森川智之、雪野五月和川澄绫子)坐镇,让人觉得还是有兴趣看完。

今天主要说的是游戏版的Gallery Fake,09年由PCPChina进行汉化。游戏版采用的是对话式推进游戏:

  1. 需要玩家在出现选择肢时候判断正确才能继续游戏,典型的一条胡同头走到黑的设计,没有任何分支,也不像《逆转裁判》那样有伪多分支的设计。
  2. 选择肢内容为对话中出现过的线索。最多五项,可能是抽象的文字线索,也可能是实在物体。
  3. 选择肢出现的场景为和游戏中其他任务进行对话寻找更新线索,对话对象可能是对手,也可能是同伴(暂时还没看到自言自语)。需要判断对话方哪一句有问题,然后用已有线索进行击破(break)。
  4. 有血条,选择错误扣除固定的1格,全部扣完后Game Over。但关键对话存活后会回血3格。

在《逆转裁判》出来之后,类似的AVG都会让人不得不拿它做个标杆进行比较,况且Gallery Fake本身还和《逆转》一样是带有主角光环的男一号+捡来的女一号这种配对。从人物设计上Gallery Fake可谓成功,这要归功于原作者,而身世背景的交代也很顺利,随着第一个故事的进行玩家可以大概了解游戏中几位主要人物的身份,同时留了一些谜作为伏笔在后续故事中展开。相比较《逆转》而言,Gallery Fake的单元剧形式同样突出主角们的特色,其他路人一笔带过,但目前为止玩到Story 4,暂时还未见到几个故事产生关联,也还没有什么出人意料的展开。如果直到最后各章还是完全独立的话,的确是个缺憾。有关联哦!

作品的背景拜原作所赐,属于比较特别的类型。艺术品鉴定本身就是一门专业性极强的科目,作品主题又涉及到敏感的赝品,所以肯定少不了黑道、警察这类的介入,但作品对这方面拿捏得十分到位,以“赝品”“复制品”为核心展开的故事包括但不限于艺术品犯罪,而且穿插故事中还有大量的艺术品和古玩知识。故事本身不好评价太多,因为必然会涉及剧透,但可以透露的是慢热类型,故事越来越好看,涉及到的艺术家和艺术史典故也越来越多,虽然可以说都是单线任务,但其故事性丝毫不差。

游戏的作画非常漂亮!背景的图细节毫不马虎,如下图的菩萨像:

其他的类似于城市街道、机场、室内场景都是如此,这一点上我想给10分。游戏版本和动画版本的人设还原度很高(除了萨拉的肤色……),如果是原作Fans的话应该能感觉到统一感,但游戏版上色有些生硬,或许是我个人喜好问题,觉得这种人物形象和背景并不是特别搭调。总体来说立绘比较生动,主角们的表情和动作变化也很有趣,作为AVG能做到这一点就是成功了。

游戏的BGM很精彩,配合艺术品题材当然要用西洋乐,因为刚开始补动画版,所以不知道OST是否统一,但游戏版本的已经足够让人满足。最近玩的一些不太热门的AVG,其OST都相当好,让人有收CD的欲望。

最后说说游戏系统,前面大概列了一下游戏关键的选择肢相关内容,个人来说,非常不喜欢游戏版的这套互动,让我没法给这个游戏打高分的原因也在于此。首先觉得不爽的是所持线索太少,只有五个,而且多数是话语线索。线索基本无法重用(有极少会用完后再次提及)。选择方式中单选的分支过于简单,反之多选的部分因为选项意思过于暧昧的问题又太让人抓狂:

这里不得不剧透一下,请原谅我。上面这个分支中要求选择“提示两套纸牌均为一人所作”的线索。其中第四条的详细内容大意为“此人做了两套纸牌”。结果正确答案中并没有此项,你可以看到几乎血条都被掏空了我才用近似穷举的方式艰难过关。类似这样的情况在游戏中还有不少——连需要选择break的对话部分都会有这种情况出现,有时候会白白费血。

游戏版的诚意足够,除了坑人的互动系统外,是个好宣传,能让没有看过原作或者动画版的玩家有兴趣回过头补完作品的其他版本。所以推荐一下。

指针参数传递和.Net中String类型的表现

本来不想对这两个老掉牙的问题进行讨论,但联系起来看确实有用。先看代码:

    class Program {
        static void Foo( string s ) {
            s = "变了";
        }

        static void Main( string[] args ) {
            string s = "原始String";
            Foo( s );
            Console.WriteLine( s );
            Console.ReadKey();
        }
    }

没错,这就是最经典的“作为引用类型的String类传参时候表现值类型特点”的例子。上述程序意料之中输出为“原始String”,但其实这并不是因为String自身特殊到所谓“引用类型表现值类型特点”,为什么这么说?看下面这个例子:

    class Person {
        public String Name;
    }

    class Program {
        static void Foo( Person p ) {
            p = new Person { Name = "李四" };
        }

        static void Main( string[] args ) {
            Person p = new Person { Name = "张三" };
            Foo( p );
            Console.WriteLine( p.Name );
            Console.ReadKey();
        }
    }

这次就清楚多了,基本都能看出输出的是“张三”,关键在于自定义class用了new这个关键字、而String类的等号便是最大的迷惑点。所以说String类在当作参数传递的时候和其他引用类型并无二致。

作为本地参数的s和p同原来的变量是完全不同的引用存在,只不过引用到的是同一块内存。使用new或者重载的=进行新内存分配后,原来的变量指向并没有发生变化。

好,那么就引出标题里面的第一个问题了“指针参数传递”,在C/C++中很容易见到这样的错误:

void Foo( int* a, int* b )
    {
    int* tmp = a;
    a = b;
    b = tmp;
    }

int main(int argc, char *argv[])
    {
    int a = 0;
    int b = 5;
    Foo( &a, &b );
    cout<<a<<","<<b<<endl;
    }

对于形参a和b而言,它们只是在栈上对于原本变量的一份拷贝,指向同一块内存,改变它的指向是没有意义的。

a(变量) --|
         |--->  0
a(参数) --|

如果没有在这上面碰过钉子的请受我一拜。如果希望改变原有指针的内容,需要直接改变被指向区域的值或者传递二级指针:

void Foo( int* a, int* b )
    {
    int tmp = *a;
    *a = *b;
    *b = tmp;
    }

void FooAlloc( int** p, int size )
    {
    *p = malloc( sizeof( int ) * size );
    }

可以说这个问题和开始提到的String的特殊表现殊途同归:

  • 归根结底,不管是指针还是引用,当作参数进行传递的时候仍然是值。
  • 指针本身的操作和指针指向内容的操作是不同的,星星太多就容易乱。同理的还有const int* i和int* const i。

还是那句话,String并不特殊,它在参数传递上表现得和其他引用类型没什么不同,但不同点在于String是一个immutable类型,所有对其进行的修改,例如SubString、连接(+)、赋值(=)等等,都会当作创建新拷贝的操作对待,这也就是导致String表现出类似于值类型特点的原因。

参考资料