                第六章  数据类型：object 
 
                    第一节  序言 
  这是 Lpc 入门的最后一节，到现在，如果前面几章都读过了，你应该 
能写出一些简单的 object，比如 room 。而且能给 room 写一些简单的 
特写，通过添加一些函数。 
 
                    第二节 作为数据类型的 object 
2.1 数据类型 object 
  在这一章中，你将了解更复杂一些的数据类型：object。一个 object 
类型的变量是指向一个装入内存的真正存在的 object 。象别的数据类 
型一样，你用 object 后面跟一个变量名来声明： 
 
    object oTest; 
 
  它有些特殊，它几乎没有什么操作符可以作用 object 这种数据类型。 
其实，也是的，让一个 room / npc 那是什么东西？而且一般的 efun， 
比如 write(), say() 也是不能操作 object 的，但是你会了解到，对于 
object 这中数据类型，有一些很重要的 efun。 
 
2.2 efun: this_object() 
  这个 efun 返回一个 object，当前被执行的函数所在的那个 object。 
也就是说，在一个文件中，this_object() 提交的 object 是这样的： 
如果这个文件写的 object 如果自己被复制装入内存单独存在，那么就 
是这个 object，如果这个文件被继承了，那么就是继承的文件进行上一 
个过程，看它是不是单独存在，也就是没有再继承的文件了。可能有些 
难也理解，让我们看这个例子，比如你写了一个 object 叫 name.c，它 
被 player.c 继承了，那么 this_object() 实际返回的是 player.c 那个 
object，而不是 name.c 。我们再来看一个使用 this_object() 的实例： 
 
  你想让一个 npc 走到一朵花旁边闻一下，但是条件是那个 npc 能自 
由运动，比如：没有晕倒，没有在战斗。 
  你可以这么做： 
 
void eventSmellFlower() 
{ 
    if( this_object()->can_act() ) 
    { 
        write( this_object()->query( "name" ) + "走到花的边上闻了闻。\n" ); 
        this_object()->add( "kee", 5 ); 
    } 
} 
 
  can_act() 在 npc.c 里面是没有定义的，而且可能它继承的任何 object 
中也没有定义。那么，如果写成这样： if ( can_act() )，driver 没有 
在当前文件和继承的所有文件里面找到 can_act()，那就会有个编译错 
误的，但是 this_object()->can_act() 就不会出现这样的错误，就算是 
can_act() 根本不存在，那么结果是返回 0 ，就是 if 测试的表达式的 
结果是假的。这样有人会问：那这个 efun 有必要存在吗？driver 在 
编译是会自动搜索它继承的所有 object，不是自然有 this_object 了 
吗？ 确实，但是有时，这个 object (暂时叫做 A )会被别的 object (B) 
继承的，别的 object (B)可能会有这个函数，而且有时候 B 可能会重载 
A 和 A 继承的函数，而你不想让那些重载的函数失去作用，那么就采用 
 this_object()-> 的形式。 
 
2.3 调用别的 Object 里面的函数 
  这就是我们引入 object 这种数据类型的最大好处了。它能让我们调 
用别的 Object 里面的函数。在上面的例子中，我们可以知道当前的 
Object 能不动。下面的例子，你可以增加一个 player 身上的钱。 
调用别的 object 里面的函数，可以用下面两种方法： 
 
object->function(parameters) 
call_other(object, "function", parameters); 
 
example: 
this_player()->add_money( "silver", 5 ); 
call_other( this_player(), "add_money", "silver", 5 ); 
 
  在某些时候( 很不精确的说法 )，mud 是一个由玩家命令触发的函数 
调用的链式反应。当一个 player 触发了一个函数调用链，那么这个 player 
就是 eufn this_player() 返回的那个 object。就是说，因为 this_player() 
依赖那个触发事件序列那个 player，那么你应该小心的使用 this_player() 
这个 efun，如果你把 this_player() 放在一些函数，这些函数别调用通 
常可能是 driver 来调用的，或者不一定是 player 来触发的，那么使用 
this_player() 最好不要出现在那些函数里面。比如 create(), setup()。 
 
2.4 lfun: init() 
  在任何时候，一个“活的”的 object，接近一个 object (进入一个新 
房间，或者另一个 object 进入同一个 room )，init() 将自动被调用。 
利用这个，你可以写一些自动触发的效果，比如，你进入一家客栈，小 
二和你打招呼，看看这样一个例子： 
 
void init() { 
    ::init(); 
    if ( this_object()->can_act() ) 
    { 
        this_object()->eventGreet( this_player() ); 
    } 
} 
 
eventGreet() 可以是下面那样： 
 
void eventGreet( object ob ) 
{ 
    if ( !ob || environment( ob ) != environment( this_object() ) ) 
    { 
        return ; 
    } 
    else 
    { 
        write( "小二说道：这位客官，您想要点什么？\n" ); 
    } 
} 
 
efun environment() 返回一个 object 所在的环境，比如一个 player 所 
在的 room，一把剑所在的 player 等等。 
 
2.5 在你的 room 里面放入一个 object 
  看下面的一个例子，你可以在一个 player 所在的房间放入一条蛇： 
 
void test() 
{ 
    object env, snake; 
 
    env = environment( this_player() ); 
    if ( objectp( env ) ) 
    { 
        snake = clone_object( "/clone/monster/snake" ); 
        if ( objectp( snake ) ) 
        { 
            snake->move( env ); 
        } 
    } 
} 
 
例子中用到了一个 efun objectp ，这个 efun 判断传入的参数是不是一 
个真实的 object，如果是就返回真，否则就是假。efun clone_object() 
则试着把一个文件调入内存，变成一个 object。最后一个函数 move， 
这个显然不是一个 efun，但是总的来说，一般会调用 efun move_object 
把一个 object 放到另一个 object 的内部。 
 
小结 ( 也是 lpc 入门的小结 ) 
  在本章，我们了解作为数据类型的 object。同时也了解一些 efun： 
this_object(), this_player() environment() clone_object() objectp() 
的使用。还有 init() 这个特别的函数的使用。 
  到了现在，你应该有足够的知识编写一些漂亮的东西了。当然，我强 
调过一点，你必须了解你为之开发的 mud，了解它的 mudlib，它的风格， 
多多阅读 mud 带的文档和说明。当然只是了解 lpc 入门 介绍的东西， 
对 lpc 的了解是很基础的，如果你想更进一步，最好的方法是，多读 
程序，多写程序，积累经验。Lpc 只是 C 的很小的一个子集，有一点点 
的特殊的东西，是很容易掌握的。 
 
maht( trill ) 
11/12/97 3:53PM 
trill@XO (tm)