.NET中继承和多态深入剖析(下)(转)
2010-01-13 09:24
429 查看
如果大家对多态的机制还不了解,可以先查看上面这2篇文章。本篇本打算使用一些例子说话,但是实际大家明白了方法表的布局结构。其实是根本不需要任何实例去讲解了。所以这一篇主要算是查缺补漏吧。
一 多态的例子
上面的列子包含了抽象方法,虚方法和接口方法,以及他们的继承和重写。实际上抽象方法和接口方法都是虚方法,只不过他们不需要也不能显示的使用virtual关键字。我们通过ILDASM来查看他们的IL有什么区别。
view plaincopy to clipboardprint?
.method public hidebysig newslot abstract virtual
instance void fun1() cil managed
{
} // end of method BaseCpu::fun1
.method public hidebysig newslot virtual
instance void fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is BaseCpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method BaseCpu::fun2
.method public hidebysig newslot abstract virtual
instance void test() cil managed
{
} // end of method ITest::test
.method public hidebysig newslot abstract virtual
instance void fun1() cil managed
{
} // end of method BaseCpu::fun1
.method public hidebysig newslot virtual
instance void fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is BaseCpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method BaseCpu::fun2
.method public hidebysig newslot abstract virtual
instance void test() cil managed
{
} // end of method ITest::test
可以看到3种方法的IL代码都有virtual关键字,说明他们全是虚方法。不同的是接口和抽象方法都有abstract方法,表示他们都是抽象的,所以非抽象类或非接口继承他们之后都需要被实现。
我们接着看继承他们的类的IL代码
view plaincopy to clipboardprint?
.method public hidebysig virtual instance void
fun1() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun1"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun1
.method public hidebysig virtual instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
.method public hidebysig newslot virtual final
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
.method public hidebysig virtual instance void
fun1() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun1"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun1
.method public hidebysig virtual instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
.method public hidebysig newslot virtual final
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
上面的Cpu类分别重写了3种方法。抽象方法和虚方法是相同的,而接口却多了一个final关键字,这样的话,此接口方法不能被子类重写。虽然他是虚方法。如果需要接口方法能被重写,需要显示的加上Virtual关键字。而如果希望一个虚方法不能被不能被子类重写,那么可以使用sealed关键字,而不能使用private来限制虚方法。 效果如下IL代码:
view plaincopy to clipboardprint?
//让接口方法可被重写,使用virtual关键字
public virtual void test()
{
throw new Exception("The method or operation is not implemented.");
}
.method public hidebysig newslot virtual
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
//---------------------------------------------------
//让虚方法不能被重写,使用sealed 关键字
public sealed override void fun2()
{
Console.WriteLine("This is Cpu fun2");
}
.method public hidebysig virtual final instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
//让接口方法可被重写,使用virtual关键字
public virtual void test()
{
throw new Exception("The method or operation is not implemented.");
}
.method public hidebysig newslot virtual
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
//---------------------------------------------------
//让虚方法不能被重写,使用sealed 关键字
public sealed override void fun2()
{
Console.WriteLine("This is Cpu fun2");
}
.method public hidebysig virtual final instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
有意思的是,如果你吧虚方法定义为private,在编码时,只能感知会更具元数据来显示出这个方法为可重写的方法,但是编译时会报错,所以不知道这算不算一个小BUG。但是在C++中,私有虚函数是有意义的,http://topic.csdn.net/t/20040805/16/3245820.html
五 总结
.NET中的继承和多态的第3篇文章终于写完了。其实自己也是从对多态懵懵懂懂的认识开始的,在网上看了好多介绍继承和多态,但很多都是给你一些自己总结的规则,看的人云里雾里,有一些也介绍到了方法表,内存结构,但是介绍的都很浅,所以自己打算稍微深入研究一下。结果一直没写下来。感觉对于继承和多态的把握关键还是在内存模型。内存结构了解了,万变不离其中。在复杂的情况也能分析的清楚。但是鉴于本人能力有限,对于内存模型那块,也是知之甚少,难免有错误的地方。
一 多态的例子
args) { Console.ReadKey(); } } interface ITest { void test(); } abstract class BaseCpu { public abstract void fun1(); public virtual void fun2() { Console.WriteLine("This is BaseCpu fun2"); } } class Cpu : BaseCpu , ITest { public override void fun1() { Console.WriteLine("This is Cpu fun1"); } public override void fun2() { Console.WriteLine("This is Cpu fun2"); } public void test() { throw new Exception("The method or operation is not implemented."); } } class NewCpu : Cpu { public override void fun1() { Console.WriteLine("This is NewCpu fun1"); } public override void fun2() { Console.WriteLine("This is NewCpu fun2"); } } class Program { static void Main(string[] args) { Console.ReadKey(); } } interface ITest { void test(); } abstract class BaseCpu { public abstract void fun1(); public virtual void fun2() { Console.WriteLine("This is BaseCpu fun2"); } } class Cpu : BaseCpu , ITest { public override void fun1() { Console.WriteLine("This is Cpu fun1"); } public override void fun2() { Console.WriteLine("This is Cpu fun2"); } public void test() { throw new Exception("The method or operation is not implemented."); } } class NewCpu : Cpu { public override void fun1() { Console.WriteLine("This is NewCpu fun1"); } public override void fun2() { Console.WriteLine("This is NewCpu fun2"); } }
上面的列子包含了抽象方法,虚方法和接口方法,以及他们的继承和重写。实际上抽象方法和接口方法都是虚方法,只不过他们不需要也不能显示的使用virtual关键字。我们通过ILDASM来查看他们的IL有什么区别。
view plaincopy to clipboardprint?
.method public hidebysig newslot abstract virtual
instance void fun1() cil managed
{
} // end of method BaseCpu::fun1
.method public hidebysig newslot virtual
instance void fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is BaseCpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method BaseCpu::fun2
.method public hidebysig newslot abstract virtual
instance void test() cil managed
{
} // end of method ITest::test
.method public hidebysig newslot abstract virtual
instance void fun1() cil managed
{
} // end of method BaseCpu::fun1
.method public hidebysig newslot virtual
instance void fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is BaseCpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method BaseCpu::fun2
.method public hidebysig newslot abstract virtual
instance void test() cil managed
{
} // end of method ITest::test
可以看到3种方法的IL代码都有virtual关键字,说明他们全是虚方法。不同的是接口和抽象方法都有abstract方法,表示他们都是抽象的,所以非抽象类或非接口继承他们之后都需要被实现。
我们接着看继承他们的类的IL代码
view plaincopy to clipboardprint?
.method public hidebysig virtual instance void
fun1() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun1"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun1
.method public hidebysig virtual instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
.method public hidebysig newslot virtual final
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
.method public hidebysig virtual instance void
fun1() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun1"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun1
.method public hidebysig virtual instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
.method public hidebysig newslot virtual final
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
上面的Cpu类分别重写了3种方法。抽象方法和虚方法是相同的,而接口却多了一个final关键字,这样的话,此接口方法不能被子类重写。虽然他是虚方法。如果需要接口方法能被重写,需要显示的加上Virtual关键字。而如果希望一个虚方法不能被不能被子类重写,那么可以使用sealed关键字,而不能使用private来限制虚方法。 效果如下IL代码:
view plaincopy to clipboardprint?
//让接口方法可被重写,使用virtual关键字
public virtual void test()
{
throw new Exception("The method or operation is not implemented.");
}
.method public hidebysig newslot virtual
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
//---------------------------------------------------
//让虚方法不能被重写,使用sealed 关键字
public sealed override void fun2()
{
Console.WriteLine("This is Cpu fun2");
}
.method public hidebysig virtual final instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
//让接口方法可被重写,使用virtual关键字
public virtual void test()
{
throw new Exception("The method or operation is not implemented.");
}
.method public hidebysig newslot virtual
instance void test() cil managed
{
// 代码大小 12 (0xc)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "The method or operation is not implemented."
IL_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
IL_000b: throw
} // end of method Cpu::test
//---------------------------------------------------
//让虚方法不能被重写,使用sealed 关键字
public sealed override void fun2()
{
Console.WriteLine("This is Cpu fun2");
}
.method public hidebysig virtual final instance void
fun2() cil managed
{
// 代码大小 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "This is Cpu fun2"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Cpu::fun2
有意思的是,如果你吧虚方法定义为private,在编码时,只能感知会更具元数据来显示出这个方法为可重写的方法,但是编译时会报错,所以不知道这算不算一个小BUG。但是在C++中,私有虚函数是有意义的,http://topic.csdn.net/t/20040805/16/3245820.html
五 总结
.NET中的继承和多态的第3篇文章终于写完了。其实自己也是从对多态懵懵懂懂的认识开始的,在网上看了好多介绍继承和多态,但很多都是给你一些自己总结的规则,看的人云里雾里,有一些也介绍到了方法表,内存结构,但是介绍的都很浅,所以自己打算稍微深入研究一下。结果一直没写下来。感觉对于继承和多态的把握关键还是在内存模型。内存结构了解了,万变不离其中。在复杂的情况也能分析的清楚。但是鉴于本人能力有限,对于内存模型那块,也是知之甚少,难免有错误的地方。
相关文章推荐
- .NET中继承和多态深入剖析(上)(转)
- .NET中继承和多态深入剖析(中)(转)
- .NET中继承和多态深入剖析(上)(
- .NET中继承和多态深入剖析(中)
- 深入剖析C++继承,多态以及隐藏(三)(类层次中的转化问题)
- 深入了解.NET中继承和多态(中)
- 深入剖析C++继承,多态以及隐藏(一)。(虚函数探究)
- 深入剖析C++继承,多态以及隐藏(三)(类层次中的转化问题)
- 深入了解.NET中继承和多态(下)
- 深入了解.NET中继承和多态(上)
- JVM--深入剖析继承与多态实现原理(合集篇)
- .NET中继承和多态深入剖析(上)
- 深入剖析C++继承,多态以及隐藏(二)。(纯虚函数以及重写与隐藏)
- .NET中继承和多态深入剖析(下)
- 深入剖析C++继承,多态以及隐藏(二)。(纯虚函数以及重写与隐藏)
- 深入剖析C#的多态三
- 菱形虚拟继承的深入剖析
- java深入学习七之封装与继承,多态
- 深入剖析C#继承机制3
- 深入剖析C#的多态(摘)