1. 覆盖和隐藏的含义及用法
在C#中,我们可以使用覆盖(override)和隐藏(new)这两个关键字来修改父类中的成员。这两个关键字的作用类似,都是为了在子类中重写父类成员的行为。
覆盖是指在子类中重写父类中的虚函数或抽象函数,并让其具有自己的实现。使用override关键字可以实现对基类成员的完全替代。具体用法如下:
public class BaseClass
{
public virtual void Method1()
{
Console.WriteLine("BaseClass.Method1");
}
}
public class DerivedClass : BaseClass
{
public override void Method1()
{
Console.WriteLine("DerivedClass.Method1");
}
}
在上面的代码中,BaseClass中有一个虚函数Method1。DerivedClass从BaseClass派生,并重写了Method1实现。在Main函数中,我们声明一个DerivedClass类型的对象,并调用了Method1。结果证明,DerivedClass的Method1实现被调用了。
static void Main(string[] args)
{
BaseClass b = new DerivedClass();
b.Method1(); // 输出:"DerivedClass.Method1"
}
隐藏则是指在子类中声明了一个与父类同名的成员,但是并没有重写父类的成员。使用new关键字可以实现成员的隐藏。具体用法如下:
public class BaseClass
{
public void Method1()
{
Console.WriteLine("BaseClass.Method1");
}
}
public class DerivedClass : BaseClass
{
public new void Method1()
{
Console.WriteLine("DerivedClass.Method1");
}
}
在上面的代码中,DerivedClass中声明了一个与BaseClass中同名的函数Method1,并使用了new关键字。在Main函数中,我们声明一个DerivedClass类型的对象,并分别调用了BaseClass和DerivedClass的Method1函数。结果证明,DerivedClass的Method1实现被调用了,而BaseClass的Method1没有被覆盖。
static void Main(string[] args)
{
BaseClass b = new DerivedClass();
b.Method1(); // 输出:"BaseClass.Method1"
DerivedClass d = new DerivedClass();
d.Method1(); // 输出:"DerivedClass.Method1"
}
2. 覆盖和隐藏的区别
虽然覆盖和隐藏都可以在子类中修改父类成员的行为,但它们之间还是有几个重要的区别。
2.1 调用方式不同
覆盖通过基类引用或指针来调用子类成员时,将会根据对象的实际类型进行调用。然而,隐藏成员总是由引用的类型来确定。具体地说:
BaseClass b = new DerivedClass();
b.Method1(); // b是一个BaseClass对象,但是实际类型是DerivedClass。输出:"DerivedClass.Method1"
DerivedClass d = new DerivedClass();
BaseClass b2 = d;
b2.Method1(); // b2本身是BaseClass类型,并不知道它的实际类型是DerivedClass。输出:"BaseClass.Method1"
DerivedClass d2 = new DerivedClass();
d2.Method1(); // d2是一个DerivedClass对象,输出:"DerivedClass.Method1"
2.2 范围不同
被覆盖的成员必须是虚函数或抽象函数,并且必须被声明在基类中,否则无法在子类中进行覆盖。然而,隐藏成员没有这个限制,它可以隐藏基类中任何成员,包括非虚函数和字段。这个区别可能会在代码维护和重构时带来额外的复杂性。
2.3 隐藏不会产生多态性
在使用隐藏时,由于成员总是由引用的类型来确定,所以不会产生多态性。具体地说,如果一个子类继承了一个基类并且隐藏了基类的某个成员,那么对于这个子类的所有对象来说,都只有子类的成员会被调用。这可能会导致程序员在运行程序时思路混乱和出现问题。相比之下,使用覆盖会产生多态性,不同的对象可能会有不同的成员实现被调用。
3. 总结
在C#中,覆盖和隐藏是重写基类成员行为的两种方式。覆盖是指重写基类中的虚函数或抽象函数,而隐藏是指声明一个与基类同名的成员,不一定要存在继承关系。覆盖和隐藏的使用方法略有不同,覆盖必须重新定义基类成员的实现,而隐藏只是在子类中声明同名的成员。另外,调用覆盖是通过对象的实际类型来决定,而调用隐藏是由引用的类型来决定,这会带来额外的复杂性。最后值得注意的是,使用隐藏不会产生多态性,可能会导致程序员产生混淆和错误。