找回密码
 注册
查看: 771|回复: 10

[讨论]从连接库里的类说开去……

[复制链接]
发表于 2005-7-23 14:05:30 | 显示全部楼层 |阅读模式
linux下的动态连接库是一些以.so为扩展名的文件,使用时可以用API打开这些文件,然后给出一个字符串,用API来查找库文件里以这个字符串命名的函数……
所以可以把一些C++类编译进这样的库文件,然后为每个类写一个函数来生成对象,比如有一个类:classA,那么就可以有这样的一个函数(当然,不是成员函数):
[code:1]
classA* new_classA()
{
    return (new classA);
}
[/code:1]
但是这样就有了一个问题:这样的库,或者说这种放在库文件里的类,应该怎样使用呢?又会有什么好处?
先说说好处:设想,一个游戏里,玩家可以购买武器,一种武器就是一个类,如果我们把新增的一些武器类放进一个库文件里,并且为每个类写一个这样的函数(仍以classA为例):
[code:1]
string desc_classA()
{
    return ( string("This is classA......") );
}
[/code:1]
另外还要有个函数告诉游戏库里有哪些类:
[code:1]
string all_classes()
{
    return ......;//返回一个字符串,里面是所有类的名字,以空格分隔
}
[/code:1]
这样,玩家在游戏里读取了这个连接库后,就会知道有哪些武器类,并且可以看到每个武器类的介绍,这样玩家就会告诉游戏:“我要购买某某武器”,这样游戏就会用武器类的名字去查找对应的new_class函数,并且创建对象,这样玩家就可以用这个新的武器了。这样可以实现很好的扩展性。
恩,的确有个问题,我们可以活得类的实例了,但是怎样使用它们呢?我们并不了解它们的细节,比如有哪些成员函数,有哪些数据成员,更不知道这些成员的意义和作用。那么有两种方法:
1.给所有的这些类都预先定义一个基类函数,这个函数里会定义一系列的虚函数,而连接库里的类,都是从这个基类派生出来的,这样就可以用基类指针来对它们操作,比如不管是什么样的枪支,总会有一个函数:shoot( int x, int y, int z ),所以通过这样的虚函数就可以操作细节未知的新类实例。
2.每个新的类里,每个成员函数都有对应的一个文字描述,用户(玩家)可以通过这些描述来理解这些函数,进而去调用它们,这样虚函数就无法胜任了。可以考虑这样的机制:
调用某个对象的某个函数时,实际上是依靠实例的地址和成员函数地址来实现的,而成员函数的地址实际是一个偏移量。
可以在每个类用,用一个static的数组来保存每个成员函数的地址(偏移量),用户会给出它要调用的函数的索引,以这个索引为数组下标获得函数地址,再结合对象地址就可以调用目标函数了。另外应该考虑,对于这样的函数,它们的函数原型应该是一样的,比如是这样的:
void* method( void* data );

那么现在有几个问题要和大家讨论:
1。我希望在游戏编程中用上述方法管理游戏中的类,比如游戏里的物品、装备、角色等。在游戏地图文件里,需要在合适的位置放置一些类的实例,比如在某些地方放点怪物之类的,在地图文件里给出的会是类的标识。标识有两种,一种是二进制数据,一种是字符串,出于效率的考虑我决定使用二进制数据。所以类的标识是在读入连接库时才会确定的。那么在制作地图时,由于不知道类的标识是什么,那么在地图里应该怎样表述类呢?
2.在游戏运行时,应该怎样管理那些类?需要实现这些:
根据类标识来创建类的实例
根据类标识来查询类的描述字符串
能够在运行期间读入新的库,或者关闭不再需要的库。
发表于 2005-7-23 22:04:07 | 显示全部楼层
缺少实际经验。

放在.so文件里的class要异常慎重,类的任何改变不但要
重新编译.so文件,它的调用文件也要重新编译。

我的建议。

自己找台机器好好实际做个实验程序好好验证一下吧。
回复

使用道具 举报

发表于 2005-7-24 07:36:13 | 显示全部楼层
[quote:5fefe14958="kakuyou"]
放在.so文件里的class要异常慎重,类的任何改变不但要
重新编译.so文件,它的调用文件也要重新编译。
[/quote]

动态链接就不必重新编译了吧
回复

使用道具 举报

 楼主| 发表于 2005-7-24 12:24:38 | 显示全部楼层
我只是在程序里用dlopen打开连接库,然后查找类的构建函数(C-Style),这样问题应该不大吧……
回复

使用道具 举报

发表于 2005-7-26 16:30:19 | 显示全部楼层
为什么要重新编译呢?
简单来说就是调用方的内存布局中为装载的类预留了空间,
这个空间大小是调用方编译时打死了的。

如果你改变了库里的类的定义,空间大小就变了,调用方
在装载对象时还是按照原来的布局方式处理,不出问题纯
粹运气。
回复

使用道具 举报

 楼主| 发表于 2005-7-26 16:55:59 | 显示全部楼层
晕,调用方都是通过基类指针来操作细节未知的类的实例,而且这些类的实例化不由调用方完成,而是由库里的函数使用new关键字来完成的。这样会出问题吗?
回复

使用道具 举报

发表于 2005-7-26 17:34:46 | 显示全部楼层
偶只说慎重,没说不能。

偶为什么说没有实际经验,因为你在烂用面向对象,还牵涉着动态
调用。
回复

使用道具 举报

 楼主| 发表于 2005-7-26 17:54:41 | 显示全部楼层
滥用?为什么呢?
回复

使用道具 举报

发表于 2005-7-26 18:09:16 | 显示全部楼层
现实中,类继承超过3层,代码基本就无法阅读和难于修改了。

引用你的一个想法

一个武器一个类

这真的需要吗?类类型和数据重叠了,你该怎么设计数据库呢?
重新书写编译出一个动态库与在数据库里加条纪录那个简单?
现实中究竟有哪个游戏系统需要每追加一种武器就修改程序的?
不觉得设计本身有什么错误?

最起码也得是
一种类型的武器一个类吧?

只能说类和对象在你的脑子里搅和了。
回复

使用道具 举报

 楼主| 发表于 2005-7-26 19:58:46 | 显示全部楼层
晕……这个……我的意思就是一种武器一个类……
回复

使用道具 举报

发表于 2005-7-26 20:10:05 | 显示全部楼层
[quote:5f4a1c628c="sjinny"]晕……这个……我的意思就是一种武器一个类…… [/quote]

偶批评的就是这个。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2025-2-8 03:51 , Processed in 0.042327 second(s), 16 queries .

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表