您的位置:首页 > 编程语言 > C语言/C++

C++与C#中包含多态性分析

2009-09-19 16:51 246 查看
与C#中包含多态性分析
包含多态性是指通过继承提供多态性。

包含多态性反映了能够在多于一个类的对象中完成同一事物的能力——用同一种方法在不同的类中处理不同的对象。例如,Customer和Vendor对象都有一个Name属性,则我们可以写一个事物来调用Name属性而不管我们所使用的是Customer对象还是Vendor对象,这就是包含多态性。包含多态性是运行时多态。
C#和C++都通过继承来为我们提供包含多态性。它们均提供了virtual关键字用于定义一个支持多态的方法。子类对于虚拟方法可以自由地提供它自己的实现,这称为重写。下面是一些关于C#虚拟方法的要点:
(1) 如果方法是非虚拟的,编译器简单地使用所引用的类型来调用适当的方法。
(2) 如果方法是虚拟的,编译器将产生代码来在运行时检查所引用的类,来从适当的类型中调用适当的方法。
(3) 当一个虚拟方法被调用时,运行时会进行检查(方法迟绑定)来确定对象和调用适当的方法,所有这些都是在运行时进行的。
对于非虚拟方法,这些信息在编译期间都是无效的,因此不会引起运行时检查,所以调用非虚拟方法的效率会略微高一些。但在很多时候虚拟方法的行为会更有用,损失的那些性能所换来的功能是很值得的。在C++和C#中包含多态性是很类似的,他们均是通过虚函数来实现的。通过下面的代码来分析它们间的异同。
C++源代码
#include<iostream>
using namespace std;
class DrawingBase
{
public:
virtual void Draw()
{
cout<<"I'm just a generic drawing object!"<<endl;
}
};
class Line:public DrawingBase
{
public :
virtual void Draw()
{
cout<<"I'm a Line !"<<endl;
}
};
class Circle:public DrawingBase
{
public:
virtual void Draw()
{
cout<<"I'm a Circle !"<<endl;
}
};
class Square:public DrawingBase
{
public:
void Draw() //(A)
{
cout<<"I'm a Square !"<<endl;
}
};
void main()
{
DrawingBase *dObj[4];
dObj[0] = new Line( ) ;
dObj[1] = new Circle( ) ;
dObj[2] = new Square( ) ;
dObj[3] = new DrawingBase( ) ;
for(int i=0;i<4;i++)
dObj[i]->Draw();
system("pause");
}

程序运行结果:
I'm a Line !
I'm a Circle !
I'm a Square !
I'm just a generic drawing object!
请按任意键继续. . .

上面程序演示了多态性的实现(程序实现的说明将在下面的C#源代码后进行)。程序中类Line、Circle和Square属于同一个类族,而且是通过公有派生而来。基类DrawingBase的函数成员Draw声明为虚函数,程序中使用对象指针来访问函数成员,这样的联编过程就是在运行中完成,实现了运行中的多态。通过基类类型的指针就可以访问到正在指向的对象的成员,这使得能够对同一类族中的对象进行统一的处理,抽象程度更高、程序更加简洁、更加高效。在源程序中的第A行,派生类Square并没有显式给出虚函数声明,这时系统就会遵循以下的规则来判断一个函数成员是不是虚函数:
(1) 该函数是否与基类的虚函数有相同的名称;
(2) 该函数是否与基类的虚函数有相同的参数个数以及相同的对应参数类型;
(3) 该函数是否与基类的虚函数有相同的返回值或者满足赋值兼容规则的指针、引用型的返回值;
如果从名称、参数以及返回值三个方面检查以后,派生类的函数满足以上的条件,就被自动确定为虚函数。
C#源代码
using System;
namespace duotai3
{
using System ;
public class DrawingBase
{
public virtual void Draw( )
{
Console.WriteLine("I'm just a generic drawing object.") ;
}
}
public class Line : DrawingBase
{
public override void Draw( )
{
Console.WriteLine("I'm a Line.") ;
}
}
public class Circle : DrawingBase
{
public override void Draw( )
{
Console.WriteLine("I'm a Circle.") ;
}
}

public class Square : DrawingBase
{
public override void Draw( )
{
Console.WriteLine("I'm a Square.") ;
}
}
public class DrawDemo
{
public static void Main(string[] args)
{
DrawingBase [] dObj = new DrawingBase [4];

dObj[0] = new Line( ) ;
dObj[1] = new Circle( ) ;
dObj[2] = new Square( ) ;
dObj[3] = new DrawingBase( ) ;

foreach (DrawingBase drawObj in dObj)
drawObj.Draw( ) ;
}
}
}

程序运行结果:
I'm a Line !
I'm a Circle !
I'm a Square !
I'm just a generic drawing object!

上面程序演示了多态性的实现。在DrawDemo类中的Main( )方法中,创建了一个数组,数组元素是DrawingBase类的对象。该数组名为dObj,是由四个DrawingBase类型的对象组成。接下来,初始化dObj数组,由于Line,Circle和Square类都是DrawingBase类的派生类,所以这些类可以作为dObj数组元素的类型。如果C#没有这种功能,你得为每个类创建一个数组。继承的性质可以让派生对象当作基类成员一样用,这样就节省了编程工作量。 一旦数组初始化之后,接着是执行foreach循环,寻找数组中的每个元素。在每次循环中,dObj 数组的每个元素(对象)调用其Draw( )方法。多态性体现在:在运行时,各自调用每个对象的Draw( )方法。尽管dObj 数组中的引用对象类型是DrawingBase,这并不影响派生类重载DrawingBase类的虚方法Draw( )。 在dObj 数组中,通过指向DrawingBase基类的指针来调用派生类中的重载的Draw( )方法。
  在DrawDemo 程序中,调用了每个派生类的重载的Draw( )方法。 最后一行中,执行的是DrawingBase类的虚方法Draw( )。这是因为运行到最后,数组的第四个元素是DrawingBase类的对象。
注意在实现类的包含多态性用虚函数实现的时候,C++与C#有一个非常重要的区别:正如我前面所说,在C++中可以在派生类中省略掉virtual虚函数关键字,但是在C#中必须在派生类中虚拟函数使用override关键字,否则编译器不会把他当成虚拟函数,该派生类也不会具有多态性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: