用语言python和C#实现动态多态性,前者简单易懂,后者复杂难理解

用语言python和C#实现动态多态性,前者简单易懂,后者复杂难理解,第1张

用语言python和C#实现动态多态性,前者简单易懂,后者复杂难理解

多态性是面向对象的三大特性之一。当同一 *** 作用于不同的对象,可以有不同的解释,产生不同的执行结果,这种特性称为多态性。在计算机语言中的多态性,一般是指调用一个同名函数,参数不同,会产生不同的执行结果。多态性可以是静态的或动态的。静态多态性,是有若干同名函数,函数的形参类型和个数不同,系统在编译时,根据调用方法的实参类型及实参的个数决定调用哪个同名方法,实现何种 *** 作。动态多态性,是调用一个名字相同,形参的类型及个数完全一样的方法,在程序运行时根据实参的不同,完成不同的 *** 作。C#运行时的多态性通过虚方法实现,复杂难懂。python函数的形参没有类型,仅仅是一个名字,当形参被实参赋值,形参将引用(代表)实参,函数就可以 *** 作实参所引用的类对象,此概念将极大简化动态多态性的实现。由于python不用编译,是解释执行的,这里只讨论动态多态性。下面的例子说明用C#语言实现动态多态性的方法。

using System;
class A
{	public void F()				//非虚方法
               {	Console.Write("  A.F");	}
	public virtual void G()                 		//虚方法
	{ 	Console.Write("  A.G");	}
}
class B:A						//A类为B类的基类
{	new public void F()				//隐藏基类的同名非虚方法F(),注意使用new
	{	Console.Write("  B.F");	}
	public override void G()   			//隐藏基类的同名虚方法G(),注意使用override
	{	Console.Write("  B.G");	}
}
class Test
{	static void F2(A aA)				//注意,参数为A类引用变量
	{	aA.G();			}
	static void Main()
	{    	B b=new B();
	     	A a1=new A();
	     	A a2=b; 		//允许基类引用变量引用派生类对象,a2引用A类派生类B的对象b
	     	a1.F(); 		//调用基类A的非虚方法F(),显示A.F
	     	a2.F(); 		//F()为非虚方法,调用基类A的F(),显示A.F
	     	b.F();  		//F()为非虚方法,调用派生类B的F(),显示B.F
	    	 a1.G(); 		//G()为虚方法,因a1引用基类A对象,调用基类A的G(),显示A.G
	     	a2.G(); 		//G()为虚方法,因a2引用派生类B对象,调用派生类B的G(),显示B.G
	     	F2(a2);  		//由于a2引用A类派生类B的对象b,调用派生类B的函数G(),显示B.G
	    	 F2(a1); 		//实参为基类A对象,调用A类的函数G(),显示A.G
	}	//最后两句调用一个名字相同,参数的类型及个数完全一样的方法F2,实参不同,完成不同的 *** 作
}

那么输出应该是:A.F A.F B.F A.G B.G B.G A.G
这里实现的要点是函数F2()的形参类型是类A,那么实参必须是A类对象或A类的派生类的对象,由于方法G()是虚方法,实参是A类对象,调用A类方法G(),实参是B类对象,调用B类方法G()。从而完成不同功能。这里涉及C#语言众多概念,十分复杂。
用Python实现相同功能,就简单多了,例子如下。

class A:
    def G(self):
        print("  A.G") 
class B(A):
#class B():    #实际上,python并不要求B类是A类子类
    def G(self):
        print("  B.G")
def F2(o):
    o.G()
aA=A()
aB=B()
F2(aA)
F2(aB)

运行后,将显示:
A.G
B.G
实际上,实现动态多态性并不要求两个类存在继承关系,即上例并不要求B类是A类子类。如果B类定义中,第4条语句变为被注释的第5条语句,仍能正常工作,但要求两个类中被函数F2()调用的方法名称必须相同。
python多态性的实现是利用了变量是对类对象的引用(代表)的规则。这里解释这个规则,变量有两部分:字符组成的变量名和保存数据的内存单元地址,令a=2,其实是将整数2保存到内存数据区,在内存变量区先保存变量名a,在其后保存整数2所在内存的地址。因此必须对变量赋值,变量才可以使用。用变量访问数据,实际是通过变量名得到地址,用地址访问数据,这种方式被称作变量a引用(代表)了整数2。如果再令a=2.3,先将浮点数2.3保存到内存数据区,变量名保持不变,仅将其后的地址换为浮点数所在内存的地址,称作变量a引用(代表)了浮点数2.3,由于变量a不再引用整数2,如果也没有其它变量引用整数2,整数2所占用的内存单元将被垃圾收集器收回。函数F2()的形参仅仅有一个名字,还未保存对应数据的地址,应是None。当程序运行后,函数F2()将被调用,形参被实参赋值。实参一定是引用了某个类对象,那么形参也将和实参一样都引用了这个类对象,即两者都引用了同一个类对象,那么通过形参就可以调用这个类对象的函数,完成指定功能。
动态多态性概念在python中被广泛使用,很多内置函数都采用python动态多态性的概念。例如python内置函数len()能检测多种数据类型的长度,也是采用了动态多态性的概念,实现步骤和上例类似。python所有数据类型都是类,包括字符串类、列表类和元组类等,这些类中都应有一个同名的检测自己长度的方法,该方法返回值为所得到的长度,假如都为G()。内置函数len()实参必定引用(代表)某一个数据类对象,将实参赋值给形参,形参将也引用(代表)这一个数据类对象,通过形参可以调用这个数据类的方法G(),将得到该数据类对象的长度返回。如果对象是字符串,则返回字符数,如果对象是列表,则返回列表中的项目数等。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5625049.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-15
下一篇 2022-12-15

发表评论

登录后才能评论

评论列表(0条)

保存