2011-07-20 70 views
0

假设我有一个类:操作符重载问题

public class Vector 
{ 
    public float X { get; set; } 

    public Vector(float xvalue) 
    { 
     X = xvalue; 
    } 

    public static Vector operator +(Vector v1, Vector v2) 
    { 
     return new Vector(v1.X + v2.X); 
    } 
} 

有一个派生类:

public class MyVector : Vector 
{ 
    public static MyVector operator +(MyVector v1, MyVector v2) 
    { 
     return new MyVector(v1.X + v2.X); 
    } 

    public MyVector(float xvalue):base(xvalue) 
    { 

    } 
} 

没有,如果我执行如下因素代码:

Vector v1 = new MyVector(10); //type MyVector 

Vector v2 = new MyVector(20); //type MyVector 

Vector v3 = v1 + v2;    //executed operator is of Vector class 

这里执行Vector的+运算符,但v1和v2的类型为MyVector,因此v3在此处为Vector类型。

为什么会发生这种情况?

+2

你所期望的是,运算符重载分辨率使用*双虚拟分派*,但实际上它使用*非虚拟分派*。如果运营商是通过双重虚拟调度解决的,但这种语言不支持该功能,那将是非常棒的。请参阅http://blogs.msdn.com/b/ericlippert/archive/2009/04/09/double-your-dispatch-double-your-fun.aspx了解更多关于此的想法。 –

+0

明白了,通过查看代码执行的问题我会说,v3是MyVector或可能是其他派生类型,但不是基于一个。真棒...而是在这里统治只是“简单”的静态函数规则的规则。 – Tigran

回答

3

因为变量v1v2的类型是Vector而不是MyVector。运算符重载是静态方法,编译器在编译时解决,而不是在运行时;他们不能被覆盖。

v1v2必须键入MyVector让编译器选择MyVector类中定义的过载。

(可选)在Vector类上定义方法public virtual Vector Add(Vector other),并且MyVector覆盖它。然后从Vectoroperator+方法调用此方法,这将按预期工作。 (MyVector然后不需要自己定义operator+)。

+1

@Tigran:不完全,但很接近。编译器查看双方的编译时类型,并列出两种类型的所有“+”运算符。然后,它会在该列表上重载解析,就好像该操作是对“运算符+(a,b)”的双参数方法的调用。 –

1

cdhowie answered一样,方法解析在编译类型中完成。

但是,如果您使用的是C#4.0,则可以尝试以下操作。

void foo() 
{ 
    Vector v1 = new MyVector(10); // type MyVector 
    Vector v2 = new MyVector(20); // type MyVector 
    Vector v3 = v1 + v2;    // Vector.operator + called 
    bar(v1, v2); 
} 

void bar(Vector p_v1, Vector p_v2) 
{ 
    dynamic v1 = p_v1;    // dynamic type 
    dynamic v2 = p_v2;    // dynamic type 
    Vector v3 = v1 + v2;    // MyVector.operator + called 
} 

要看到的,而不是在编译时(如在foo())感知型,在bar()方法,该方法调用决议将在运行时完成,使用的真实类型的v1v2

:-)

P.S:类时滞类型在运行时分辨率可慢,安全性较差(如本应在编译时被抓的错误将在执行过程中被发现)。

+0

不错,谢谢。 – Tigran