代码之家  ›  专栏  ›  技术社区  ›  IS4

如何在CLR中使用多重继承?

  •  0
  • IS4  · 技术社区  · 7 年前

    我遇到了一些像 this CLR实际上支持多重继承(多个基类型)(但在C和其他语言中不支持)。基于本文所描述的方法,它看起来更像是一个技巧而不是直接的支持,但我仍然想知道它应该如何工作。

    如果创建自定义VTable并在VTFixup中使用它实际上可以实现多重继承,那么如何在CIL中实现并使用它呢?

    0 回复  |  直到 7 年前
        1
  •  0
  •   Yennefer    7 年前

    当前CLR不支持多重继承。然而,事实证明(看看标准的c++)编译器可以模拟多重继承,即使它只支持单一继承。 实际上,这就是MC++所做的。

    理想情况下,您至少需要:

    • 能够声明多重继承
    • 允许类型系统理解它
    • 重写方法时解决歧义
    • 处理构造函数和终结器

    多重继承仿真

    假设你想上课 A 从类继承的 地下一层 地下二层 . 假设课程是:

    public class B1
    {
        public void MethodDeclaredInB1();
    }
    
    public class B2
    {
        public void MethodDeclaredInB2();
    }
    

    从概念上讲,编译器(泛型编译器可以做的)可以在幕后完成以下工作: 创建一个新类型, A1级 这是一个有两个字段的简单对象。代码可能如下所示:

    public sealed class A1
    {
        public B1 B1;
        public B2 B2;
    }
    

    然后,在编译时,通过访问以下字段透明地转换调用:

    你的高级代码

    A a = new A();
    a.MethodDeclaredInB1();
    a.MethodDeclaredInB2(); 
    

    可以上交(暂时不考虑构造函数):

    A1 a = new A1();
    a.B1.MethodDeclaredInB1();
    a.B2.MethodDeclaredInB2();
    

    类型系统管理

    这很困难,因为编译器不能使用语言的标准规则,但需要使用编译时发出的helper方法来执行类型检查。

    你的高级代码

    Object o = new A();
    B1 b = o as B1;
    b.MethodDeclaredInB1();
    

    可以变成

    Object o = new A1();
    B1 b = AsOperator(o, typeof(B1));
    b.MethodDeclaredInB1();
    

    在哪里 AsOperator 方法可以是一个通用方法,该方法使用伪代码执行此操作:

    method AsOperator: instance i1 , type t1 -> returns instance of type t1
    t2 <- get the runtime type of instance i1
    if t2 is not a compiler generated object (e.g. A1) then
        use the standard type system checking (this is trivial and we skip it here)
    else
        for each child type c1 in t2->parent classes
            if c1 is subtype of t1 or it is exactly the same as t1 then return the corresponding field (this is a trivial task too) and we are done
    
        no match, return null
    

    这个 A操作员 也需要有 CastOperator (它的作用与此相同,但不是返回null,而是抛出 InvalidCastException ). 这些新运算符必须分布在代码中,因为编译器不能总是使用静态分析来确定对象实例的内容。

    重写方法时解决歧义 这是一个棘手的问题,因为你必须解决的问题,如 Diamond Problem . 幸运的是,这是一个众所周知的问题,您可以找到一个解决方案(至少是次优的)。 调用继承方法和实例方法时,编译器需要修补 this 指向正确基类的指针。

    处理构造函数和终结器

    构造函数是终结器,终结器是特定的虚拟/继承方法。特别是,在C++中,被构造/销毁的对象的类型随时间而变化,在层次结构的结尾停止。在构造/销毁对象时,您必须面对虚拟方法调用,尽管这不是一种好的做法。

    旁注

    MC++编译器发出一个值类型,该值类型使用这些概念并重写操作符,以获得所需的语义。

    构建一个满足您要求的编译器很有挑战性,但确实很难,因为您首先必须为所有新情况定义一个正确的行为(例如,考虑diamond问题),而好处可能是有限的。 使用接口而不是类,可能有助于避免多重继承。