Polymorphism (not) broken with visitor pattern in C# (and new instead of override)
I have the following code:
class Visitor
{
internal virtual void Visit(Node n) { }
}
class VisitorSpecial : Visitor
{
internal new void Visit(Node n) { }
}
class Base
{
internal virtual void Accept(Visitor v) { }
internal virtual void Ac开发者_如何学JAVAcept(VisitorSpecial v) { }
}
class Node : Base
{
internal override void Accept(Visitor v){ v.Visit(this); }
internal override void Accept(VisitorSpecial v){ v.Visit(this); }
}
Is there any reason why the
Accept(Visitor v)
method would be chosen when calling
new Node().Accept(new VisitorSpecial())
Update: OK, my bad, I realized I was using "new" in the visitor instead of override. Now I know why "new breaks polymorphism". This makes my question totally stupid. Thanks for the help.
Not sure why it would be chosen (it could literally be because it is first in the class declaration and matches the argument provided), but the
Accept(VisitorSpecial v)
functions are pointless in this situation and seems to be down to a misunderstanding of polymorphism. Try the following to see why:
class Visitor
{
internal virtual void Visit(Node n) { Console.WriteLine("In normal visitor"); }
}
class VisitorSpecial : Visitor
{
internal override void Visit(Node n) { Console.WriteLine("In special visitor"); }
}
class Base
{
internal virtual void Accept(Visitor v) { }
}
class Node : Base
{
internal override void Accept(Visitor v){ v.Visit(this); }
}
With the above, calling
someNode.Accept(new VisitorSpecial());
will produce the output
> In special visitor
I think you ask the question for a specific language (C#?). It's up to the language to select the most appropriate overload (note: not override!) given an argument. That depends on the type of function lookup it uses: static (compile-time) or dynamic (run-time).
In case your language uses static binding, it will probably choose the most specific call, in this case, n.Accept( new VisitorSpecial() )
would call the second overload. However,
Visitor v = new VisitorSpecial();
n.Accept( v );
would be statically bound to the Node::Accept( Visitor )
function.
In case the language uses dynamic binding, it can choose the called function based on the actual runtime type of the argument.
In general, you can work around the problem altogether by not using overloading, which is merely syntactic sugar: make a distinction between AcceptVisitor
and AcceptSpecialVisitor
. Add an AcceptManager
and AcceptJustSimplyMy
too.
精彩评论