写在前面,在C#中派生类实例化时,首先会调用基类的构造方法,然后再调用派生类的构造方法。在C#中可以在派生类中对基类中使用virtual、override、abstract声明的方法进行重写(override)。同样也可以在派生类中使用new 关键字对基类相应的方法进行覆盖。那么这两种方式究竟有多大区别呢?下面开始试验.....
一、范围
// 基类A
public class A
{
//虚方法
public virtual void A_Method()
{
Console.WriteLine("这是基类A的方法!");
}
}
在派生类B中对基类虚方法A进行重写(override)和覆盖(new)
1.改变方法主体
override(可以使用)
public override void Print()
{
Console.WriteLine("这是派生类B对基类方法的重写!");
}
new(可以使用)
public new void Print()
{
Console.WriteLine("这是派生类B对基类方法的覆盖!");
}
2.改变方法返回值
override(不可使用,提示返回类型要与基类成员匹配)
public override string Print()
{
Console.WriteLine("这是派生类B对基类方法的重写!");
return "STR";
}
new(可以使用)
public new string Print()
{
Console.WriteLine("这是派生类B对基类方法的覆盖!");
return "STR";
}
3.添加参数
override(不可使用,提示没有找到适合的方法来重写)
public override void Print(int a)
{
Console.WriteLine("这是派生类B对基类方法的重写!");
}
new(可以使用,但是会产生一个警告,提示不会隐藏可访问成员,不需要关键字new)
public new void Print(int A)
{
Console.WriteLine("这是派生类B对基类方法的覆盖!");
}
这里我们做一个测试,看看这个警告是什么意思
// 基类A
public class A
{
//A的构造方法
public A()
{
Console.WriteLine("这是基类A的构造方法!");
this.Print(); //打印
}
//虚方法
public virtual void Print()
{
Console.WriteLine("这是基类A的虚方法!");
}
}
//派生类B,派生自基类A
public class B:A
{
public B()
{
Console.WriteLine("这是派生类B的构造方法!");
this.Print(); //重载
this.Print(3); //重载
}
//覆盖基类的虚方法
public new void Print(int a)
{
Console.WriteLine("这是派生类B对基类方法的覆盖!,输出"+a);
}
}
class Program
{
static void Main(string[] args)
{
B b =new B();
}
}
输出结果:
这是基类A的构造方法!
这是基类A的虚方法!
这是派生类B的构造方法!
这是基类A的虚方法!
这是派生类B对基类方法的覆盖!,输出3
结果分析:可以发现,基类使用了自己的方法,派生类进行了一个重载,也就是这样写是对函数的重载,所以那个new确实没啥用,应该不写的。
4.添加其他修饰符
override(不可使用,提示标记为overrid的成员不可标记为virtual或new)
public override virtual void Print()
{
Console.WriteLine("这是派生类B对基类方法的重写!");
}
new(可以使用)
public new virtual void Print()
{
Console.WriteLine("这是派生类B对基类方法的覆盖!");
}
二、new和override在基类和派生类中的区别
1.对于基类的虚方法方法进行覆盖(new)
// 基类A
public class A
{
//A的构造方法
public A()
{
Console.WriteLine("这是基类A的构造方法!");
this.Print(); //打印
}
//虚方法
public virtual void Print()
{
Console.WriteLine("这是基类A的打印方法!");
}
}
//派生类B,派生自基类A
public class B:A
{
public B()
{
Console.WriteLine("这是派生类B的构造方法!");
this.Print(); //打印
}
//覆盖基类的虚方法
public new void Print()
{
Console.WriteLine("这是派生类B对基类打印方法的覆盖!");
}
}
class Program
{
static void Main(string[] args)
{
B b =new B(); //实例化B
}
}
输出结果:
这是基类A的构造方法!
这是基类A的打印方法!
这是派生类B的构造方法!
这是派生类B对基类打印方法的覆盖!
结果分析:可以发现,覆盖只会改变派生类的方法。
2.对于基类的虚方法方法进行重写(override)
// 基类A
public class A
{
//A的构造方法
public A()
{
Console.WriteLine("这是基类A的构造方法!");
this.Print(); //打印
}
//虚方法
public virtual void Print()
{
Console.WriteLine("这是基类A的打印方法!");
}
}
//派生类B,派生自基类A
public class B:A
{
public B()
{
Console.WriteLine("这是派生类B的构造方法!");
this.Print(); //打印
}
//重写基类的虚方法
public override void Print()
{
Console.WriteLine("这是派生类B对基类方法打印方法的重写!");
}
}
class Program
{
static void Main(string[] args)
{
B b =new B(); //实例化B,输出相关内容
}
}
输出结果:
这是基类A的构造方法!
这是派生类B对基类方法打印方法的重写!
这是派生类B的构造方法!
这是派生类B对基类方法打印方法的重写!
结果分析:可以发现,派生类的方法改变了,但是基类中的虚方法Print也被改变了。。。
三、new和override它们的影响范围
1.使用new
// 基类A
public class A
{
//A的构造方法
public A()
{
Console.WriteLine("这是基类A的构造方法!");
this.Print(); //打印
}
//虚方法
public virtual void Print()
{
Console.WriteLine("这是基类A的打印方法!");
}
}
//派生类B,派生自基类A
public class B :A
{
public B()
{
Console.WriteLine("这是派生类B的构造方法!");
this.Print(); //打印
}
//覆盖基类的虚方法
public new void Print()
{
Console.WriteLine("这是派生类B的打印方法(new覆盖)!");
}
}
//派生类C,派生自类B
public class C :B
{
public C()
{
Console.WriteLine("这是派生类C的构造方法!");
this.Print(); //打印
}
}
class Program
{
static void Main(string[] args)
{
C c =new C(); //实例化C
}
}
输出结果:
这是基类A的构造方法!
这是基类A的打印方法!
这是派生类B的构造方法!
这是派生类B的打印方法(new覆盖)!
这是派生类C的构造方法!
这是派生类B的打印方法(new覆盖)!
结果分析:基类的方法没有变化,派生类在进行派生会使用派生类的方法。
2.使用override
// 基类A
public class A
{
//A的构造方法
public A()
{
Console.WriteLine("这是基类A的构造方法!");
this.Print(); //打印
}
//虚方法
public virtual void Print()
{
Console.WriteLine("这是基类A的打印方法!");
}
}
//派生类B,派生自基类A
public class B :A
{
public B()
{
Console.WriteLine("这是派生类B的构造方法!");
this.Print(); //打印
}
//重写基类的虚方法
public override void Print()
{
Console.WriteLine("这是派生类B的打印方法(override重写)!");
}
}
//派生类C,派生自类B
public class C :B
{
public C()
{
Console.WriteLine("这是派生类C的构造方法!");
this.Print(); //打印
}
}
class Program
{
static void Main(string[] args)
{
C c =new C(); //实例化C
}
}
输出结果:
这是基类A的构造方法!
这是派生类B的打印方法(override重写)!
这是派生类B的构造方法!
这是派生类B的打印方法(override重写)!
这是派生类C的构造方法!
这是派生类B的打印方法(override重写)!
结果分析:果然基类和派生类的都变了。
总结:
使用new对基类方法进行覆盖时,会产生一个重载,这时候基类的方法依然存在,并且未发生改变,这里更准确的说法应该是一个方法重载,而且是一种更高级的重载,它在进行重载的时候甚至可以做到参数类型都不相同,有些地方把它成为隐藏。但在使用override就完全不同了,它是真正的改变了方法,它要求返回值、参数、等等必须是完全相同的,唯一能够改变的只能是方法的主体。不过它确实做得很彻底,因为它连基类中对应的函数都被重写了......使用new的时候可以进行向下的修改也就是派生类的派生类会发生改变,而使用override时会将所有类都进行修改。