C#基础巩固——重写(override)修饰与覆盖(new)修饰的区别

       写在前面,在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时会将所有类都进行修改。

你可能感兴趣的:(C#基础,编程学习,C#)