3

我正在设计我自己的 OO 语言,并且一直很开心,直到遇到异常。在我看来,异常打破了封装。

例如,如果 A 类有 B 类的对象,B 有 C,C 有 X,这会向 A 抛出异常,那么 A 中的代码不仅要知道 X,还要知道 B 和 C 才能正确处理。您可以这样说,因为如果您将 C 替换为 D,则必须更改异常的处理程序以从调用堆栈中提取相关信息。

我能想到的解决此问题的唯一方法是将异常作为类 API 的一部分,以便它们一次向调用堆栈传播一个调用者。他们应该以自己的方式重新中断异常。

这是一个例子。Trend 是一个用于分析统计趋势的类,它有一种方法,斜率,用于从两点计算直线的斜率。

method slope
    given
        Point 1st
        Point 2nd
    returns
        Number m
    except
        when infinite slope

    m gets
        ( 2nd's y - 1st's y ) / ( 2nd's x - 1st's x )
    except
        when any divide by zero
            declare infinite slope
        when overflow of ( 2nd's y - 1st's y )
            declare infinite slope
        when overflow of ( 2nd's x - 1st's x )
            instead do m gets 0
        when overflow of ( 2nd's y - 1st's y ) / ( 2nd's x - 1st's x )
            declare infinite slope
        when any underflow
            instead use 0

end of method slope

有一个更好的方法吗?

4

3 回答 3

2

现实世界的异常属于以下三个粗略类别之一:

  • 当底层运行时发生致命错误时抛出系统异常,例如内存不足、堆栈溢出或安全违规。这些一般不应该被抓到,而且在很多情况下是不能被抓到的。他们基本上使用异常系统来(相对)优雅地关闭系统并将最终的堆栈跟踪报告给开发人员。

  • 当代码做错事时会抛出程序异常。诸如无效参数、在空指针上调用方法、越界错误之类的事情。这些不应该被捕获:相反,导致它们被抛出的代码应该被修复。他们使用异常系统来避免使用或多或少的冗余assert系统来完成大部分相同的事情。

  • 当发生无法以编程方式防止的不良情况时,会引发运行时异常。当发生意外情况时会抛出它们,但这种情况非常罕见,以至于您不想用错误代码等混淆主 API。这些是文件 IO 错误、网络问题、解析错误等。这些异常通常将特定于抛出它们的 API。这些是通常应该捕获的唯一类型的异常。

如果您同意上述细分,那么封装只会影响第三类。对于另外两个,异常没有被代码捕获,所以没关系。对于第三种异常,是的,我认为您通常应该捕获异常并将其转换为适合重新抛出它的层的不同异常。这就是为什么其他语言中的大多数异常系统都支持诸如“InnerException”之类的东西,您可以在其中附加导致当前异常的先前较低级别的异常。

于 2012-03-16T18:18:49.340 回答
0

如果将 C 替换为 D,则必须更改异常的处理程序以从调用堆栈中提取相关信息。

不是通常实现异常处理程序的方式。在编译 A 时,被调用的中间类甚至可能不存在,因此将这种依赖关系构建到 A 中不仅困难,而且原则上是不可行的。

于 2012-03-16T04:33:50.083 回答
0

我同意异常听起来比面向对象和类更结构化。

但是,允许解决处理错误。

例如,……从调用堆栈中提取相关信息。

您在 C++ 中的示例 - 类似伪代码

class XClass {
  public: 
    void doSomething() { throw new MyException(); }
}

class CClass {
  public: 
    XClass X;
}

class BClass {
  public: 
    CClass C;
}

class AClass {
  public: 
    BClass B;
}

void main()
{
  AClass A = new AClass ();

  // exception here:
  A.B.C.X.doSomething();
}

关于异常,“A”对象不必知道“X”,反之亦然。应该有一个异常堆栈,所有对象都添加或删除执行数据。

“纯 C”没有例外,但是可以模拟它们。您可能想搜索“setjmp”库,看看这些函数能否与堆栈交互。这些知识可以帮助您实现异常:

http://www.cplusplus.com/reference/clibrary/csetjmp/

PD Offtopic 建议:将 c++ 命名空间或 pascal 模块添加到您的程序中。lang.,你不会后悔的。

于 2012-04-30T22:55:15.173 回答