• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
悟空的天空
天马行空
博客园    首页    新随笔    联系   管理    订阅  订阅
浅谈new、override、virtual

简要: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 用在派生类中,表示对基类虚方法(属性)的重写。

五、      虚方法

对于非虚的方法,无论被其所在类的实例调用,还是被这个类的派生类的实例调用,方法的执行方式不变。而对于虚方法,它的执行方式可以被派生类改变,这种改变是通过方法的重载来实现的。

posted on 2009-07-20 09:05  悟空  阅读(250)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3