简要:new、override、virtual、new和override的区别、虚方法
一、new
在C#中,new这个关键字使用频率非常高,主要有3个功能:
a) 作为运算符用来创建一个对象和调用构造函数。
b) 作为修饰符。 隐藏作用!
c) 用于在泛型声明中约束可能用作类型参数的参数的类型。
a) 作为运算符
new关键字的作用的计算需要分配的内存大小和分配内存。
格式:类名对象名 = new 类型名();
解释“new 类型名()“:
解释:其实这里暗藏了一些东西。在实例化类,其实.net为你做了两件事。“new”分配空间;“new 类型名()” 如果分配成功就在调用实例构造函数 初始化非静态成员变量(实例变量) 如果内存没有所需的大小 则调用GC 进行垃圾回收 腾出一部分空间来。 GC的作用就是管理内存的,不像C++需要程序员自己处理内存上的垃圾回收)
。而构造函数是已经封装了很多方法等,为了是度量所需的内存空间大小以及状态初始化。
当两个类名一致的很好理解,当不同时,new后的类就是派生类。
例如:IUser user = new UserA();
同理:baseClass newClass = new class1();//baseClass基类;class1派生类
这样好处就是,声明给一个基类(泛型),我不用具体这个类型是什么。只要关心new后实例化的类是哪个,就可以运用它的方法,属性等等。
|
namespace test { public class MyClass { public int a = 2; public int b = 1; public int c = 0; public MyClass() { Console.WriteLine("MyClass:默认构造函数"); } public MyClass(int a, int b) { Console.WriteLine("MyClass带参构造:a={0}, b={1}.", a, b); } public virtual void Add(int a, int b) { a = 2; b = 1; c = a + b; Console.WriteLine("c={0}", c); } } public class MyClass2 : MyClass { public MyClass2() { Console.WriteLine("MyClass2:默认构造函数"); } public MyClass2(int a, int b) { Console.WriteLine("MyClass2带参构造:a={0}, b={1}.", a, b); } public override void Add(int a, int b) { c = a *b; Console.WriteLine("c={0}", c); //base.Add(2,1); } } public class runMyApp { static void Main() { MyClass my = new MyClass2();//派生类分配内存空间,my对象只调用了MyClass2中的方法 my.Add(3, 2); System.Console.Read(); } } } /* Output: MyClass:默认构造函数 MyClass2:默认构造函数 C=6; */ |
b) 使用新的派生成员替换基类的成员需要使用 new 关键字。如果基类定义了一个方法、字段或属性,则 new 关键字用于在派生类中创建该方法、字段或属性的新定义。new 关键字放置在要替换的类成员的返回类型之前
|
C# public class BaseClass { public void DoWork() { } public int WorkField; public int WorkProperty {get { return 0; }} } public class DerivedClass : BaseClass { public new void DoWork() { } public new int WorkField; public new int WorkProperty {get { return 0; }} } |
使用 new 关键字时,调用的是新的类成员而不是已被替换的基类成员。这些基类成员称为隐藏成员。如果将派生类的实例强制转换为基类的实例,就仍然可以调用隐藏类成员。例如:
|
C# DerivedClass B = new DerivedClass(); B.DoWork(); // Calls the new method. BaseClass A = (BaseClass)B; A.DoWork(); // Calls the old method. |
二、 Override
要扩展或修改继承的方法、属性、索引器或事件的抽象实现或虚实现,必须使用 override 修饰符。Override关键字主要是提供派生类对基类方法的新实现,重写的基类方法必须和Override的方法具有同名且参数相同的函数。基方法必须是 virtual、abstract 或 override 的。此关键字不可以用于重写非虚方法和静态方法。
与此同时,override 声明不能更改 virtual 方法的可访问性。override 方法和 virtual 方法必须具有相同的访问级别修饰符。 不能使用修饰符 new、static、virtual 或 abstract 来修改 override 方法。 重写属性声明必须指定与继承属性完全相同的访问修饰符、类型和名称,并且被重写的属性必须是 virtual、abstract 或 override 的。
|
C# class TestOverride { public class Employee { public string name; // Basepay is defined as protected, so that it may be // accessed only by this class and derrived classes. protected decimal basepay; // Constructor to set the name and basepay values. public Employee(string name, decimal basepay) { this.name = name; this.basepay = basepay; } // Declared virtual so it can be overridden. public virtual decimal CalculatePay() { return basepay; } } // Derive a new class from Employee. public class SalesEmployee : Employee { // New field that will affect the base pay. private decimal salesbonus; // The constructor calls the base-class version, and // initializes the salesbonus field. //派生类构造函数并调用基类构造函数用“:base” public SalesEmployee(string name, decimal basepay, decimal salesbonus) : base(name, basepay) { this.salesbonus = salesbonus; } // Override the CalculatePay method // to take bonus into account. public override decimal CalculatePay() { return basepay + salesbonus; } } static void Main() { // Create some new employees. SalesEmployee employee1 = new SalesEmployee("Alice", 1000, 500); Employee employee2 = new Employee("Bob", 1200); Console.WriteLine("Employee4 " + employee1.name + " earned: " + employee1.CalculatePay()); Console.WriteLine("Employee4 " + employee2.name + " earned: " + employee2.CalculatePay()); } } /* Output: Employee4 Alice earned: 1500 Employee4 Bob earned: 1200 */ |
三、 Virtual
关键字不可以与static、abstract、private、override一起使用。Virtual关键
字又是和override紧密不可分的,如果要实现Virtual方法就必须要使用override或new关键字(new和override产生的机理不同)。
四、 了解何时使用 Override 和 New 关键字
实例:
|
namespace ConsoleApplication1 { public class Program { public class Root { public void Write() {System.Console.WriteLine("Root");} public virtual void Write2() {System.Console.WriteLine("Root2 virtual");} } public class Child : Root { public new void Write() {System.Console.WriteLine("Child");} public override void Write2() { System.Console.WriteLine("Child override Virtual"); base.Write();//调用基类的方法。 } } static void Main(string[] args) { Root root = new Root(); root.Write(); root.Write2(); System.Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~`\r\n"); //已经屏蔽了派生类 root = new Child();//基类变量指向派生类对象的实例化看六的解释!!! root.Write();//调用父类的方法 root.Write2();//调用子类重写的方法 System.Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~`\r\n"); Child child = new Child(); child.Write();//调用子类的方法 child.Write2();调用子类的方法 System.Console.Read(); } } } |
Out:
从这段代码可以看出new 和 override的区别:
除了使用base、强制型转换来调用出父类的方法。只要虚方法被override,则一定调用这个重写的方法。但是new就不能屏蔽。特别对于基类变量指向派生类对象的实例化和派生类实例化。
总结:
l 对同一成员同时使用 new 和 override 是错误的做法,因为这两个修饰符的含义互斥。new 修饰符会用同样的名称创建一个新成员并使原始成员变为隐藏的。override 修饰符会扩展继承成员的实现。
l virtual 用在基类中,指定一个虚方法(属性),表示这个方法(属性)可以重写。
override 用在派生类中,表示对基类虚方法(属性)的重写。
五、 虚方法
对于非虚的方法,无论被其所在类的实例调用,还是被这个类的派生类的实例调用,方法的执行方式不变。而对于虚方法,它的执行方式可以被派生类改变,这种改变是通过方法的重载来实现的。
浙公网安备 33010602011771号