游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2264|回复: 4

关于排除逻辑错误

[复制链接]

125

主题

364

帖子

396

积分

中级会员

Rank: 3Rank: 3

积分
396
QQ
发表于 2006-11-1 01:21:00 | 显示全部楼层 |阅读模式
问题是

我有三个函数 分别是 Initialize   InitEntry  Restore
在 Initialize 我这样调用  

  1. {
  2.       ...
  3.       Restore();
  4.       InitEntry();
  5. }
复制代码


InitEntry()被设成了虚函数。
我没有直接将 Initialize  和 Restore() 都写为虚函数。

再另一个类中, 我错误的先在 InitEntry中初始化东西,
然后 以为 Restore() 会再 InitEntry之后执行。

于是就造成了一个逻辑错误。后来找啊找,跟啊跟找到了。

我想问的是,这种错误,除了细心外,什么方法可以
很快缩小错误范围以避免东找西找,看源码,看调试码?

谢谢 斑竹大人 回答。(跟C++硬扯的 用到了虚函数)

2

主题

112

帖子

112

积分

注册会员

Rank: 2

积分
112
发表于 2006-11-1 02:16:00 | 显示全部楼层

Re:关于排除逻辑错误

居然点名请BZ回答……呵呵。

不是回答,只是感觉楼主找人review下代码比较好

8

主题

716

帖子

716

积分

高级会员

Rank: 4

积分
716
发表于 2006-11-1 10:45:00 | 显示全部楼层

Re:关于排除逻辑错误

以我对LZ的说明的理解,解答如下:
我猜测此处应该有一BaseClass和Derive1和Derive2
对于Derive1和Derive2都会出现的
Initialize()
{
      ...
      Restore();
     InitEntry();
}
其中...应该是各个派生类“不相同的地方”,这里即可将这部分的代码放一个比如virtual void BeforeRestore()中,由各子类各自实现
而接下来的Restore()和InitEntry(),不论是否虚函数,其调用顺序既然有要求,则最终结果如下

class Base
{
public:
    void Initialize()
   {
    BeforeRestore();
    Restore();
    InitEntry();
   }

protected:
    virtual void BeforeRestore() {};
    virtual void Restore() {};
    virtual void InitEntry() {};
}

PS,你这个问题正好承接之前我提到的,链接:http://bbs.gameres.com/showthread.asp?threadid=66814
楼主所遇到的问题,主要就是如何在设计接口时就可以努力避免一些不必要的逻辑问题,以及在需求发生变更的时候(例如过一段时间又要求先InitEntry后Restore,或是其中又要穿插新的代码),这个时候,对于client(我对使用者的称呼,可能是你自己或是其他程序)而言,因为面向他们的只需要调用public的Initialize,底层不可见(此即封装的意义),这时即使发生改动,逻辑层代码不需要改变,而只是需要sync最新底层代码重新编译即可。
当然,进一步引发的问题就是,如果情况严重到连interface都需要变动(改名、新增、删除),这样一方面代表前期设计的不良;一方面代表考虑欠周全。

个人认为,在很长一段时间内,c++ programmer都停留在c with class阶段,而上升到OO需要一段时间,当code积累到足够经验后,再参与过一个中、大型case的design,才能谈得上有点architect的味道

所以强烈建议大家细细咀嚼《Exceptional C++ Style》17、18、19章!!!

2

主题

112

帖子

112

积分

注册会员

Rank: 2

积分
112
发表于 2006-11-1 12:22:00 | 显示全部楼层

Re:关于排除逻辑错误

既然只有InitEntry是虚函数,那么意味着lz的initialize函数中规定的执行顺序是一个设计需求。说明Restore()必须在InitEntry()之前调用,应该强制自己遵守这个设计要求。

假如Restore和InitEntry的调用顺序是可变的,又因为这些东西在Base Class里面实现,可能在以后会不小心忘记,那么不如把Restore分成PreRestore()和PostRestore()两部分,写作:
void initialize()
{
  PreRestore();
  InitEntry();
  PostRestore();
}
我想这样就不存在忘记的问题了,看名字一目了然。

但同样我想质疑一下lz这个东西的设计,既然InitEntry()是虚的,而Restore()的调用顺序可能需要和InitEntry()有关。假如Restore()不作为虚函数实现的话,以后会出现问题的吧?设想拿一个基类的指针去调用initialize()....

125

主题

364

帖子

396

积分

中级会员

Rank: 3Rank: 3

积分
396
QQ
 楼主| 发表于 2006-11-1 16:32:00 | 显示全部楼层

Re:关于排除逻辑错误

个人作下总结。 综合楼上和斑竹大人的回答。 我得出的结论就是,

经验不足, 需要自我发现更多的这种因为设计接口而导致的错误。然后
逐渐的形成好的设计习惯, 而不是一开始就设计错误了。 然后需要反复变更。
或由于  害怕影响lcient , 而留着那些看着讨厌的接口。

现在我养成的习惯是  不管接口的安排的多么错误我都不敢动,于是导致
垃圾接口越来越多。

另外,我贴的 Initialize 里的 Restore 和 InitEntry是 错误的顺序。 我本意
先 InitEntry  后 Restore,  而我却错误的 调用成 Restore InitEntry。

另外  是否可以让 Restore 直接依赖于 InitEntry 返回的状态。 如果广泛使用这种
向上依赖的 设计,我认为可能会有很多 这样的状态变量。

另外, 一种就是, 不在 Initialize 里调用 Restore, 而是 在InitEntry里调用。
这样,InitEntry就一定在 Restore之前被执行。

综合这几种情况, 和斑竹给的链接,决定遵照 public 少量的接口。 而其他都为protected,
以保证 子类可 访问。 而调用顺序则 Initialize 里调用 InitEntry , InitEntry 里调用
Restore.  

如果 按   FantasyDR   所说, 则按照这样设计,  PreInitEntry   PreRestore  PostRestore  PostInitEntry   (非常感谢)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-25 18:12

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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