C#继承和多态中的new和override

    近期要从头搭建一个软件的基础架构,在了解过需求后,开始着手对代码结构进行设计。其中不免要对C#这一面向对象语言的继承和多态有着更清晰的认识,以更好地利用这些性质。

   本文代码Git地址:https://github.com/houxiaoxuan/CSharpBasicCodePractice(如果对您有帮助,还请不吝给个Star,谢谢!)

    先上dj,先上dj!

public class Employee
{
    private string _firstName;
    public string FirstName
    {
        get => _firstName;
        set => _firstName = value;
    }
    private string _lastName;
    public virtual string LastName
    {
        get => _lastName;
        set => _lastName = value;
    }
    public void IMethod() { Console.WriteLine("Method of Employee"); }
    public virtual void IMethodForNew() { Console.WriteLine("New Method of Employee"); }
    public virtual void IMethodForOverride() { Console.WriteLine("Override Method of Employee"); }//abstract修饰的话(注意基类也要用abstract修饰)被override亦然,接口同理
        
}

public class Manager : Employee
{
    private string _firstName;

    // Notice the use of the new modifier:
    public new string FirstName//new出来的属性在Manager对象中会隐藏基类的属性(即实际上基类对象的该属性仍存在,可通过将其隐式转换为基类对象或赋值给基类对象并对其进行修改,达到基类中被隐藏属性的修改),即new不会修改基类对象被隐藏属性的引用地址
    {
        get => _firstName;
        set => _firstName = value + ", Manager";
    }
    private string _lastName;
    public override string LastName//重写后的该属性即使转换或赋值给基类对象,即override会修改基类对象该属性的引用地址
    {
        get => _lastName;
        set => _lastName = value;
    }
    public new void IMethod() { Console.WriteLine("Method of Manager"); }
    public new void IMethodForNew() { Console.WriteLine("New Method of Manager"); }
    //注意此处new会隐藏基类中的方法(无论原基类中被new的方法或属性,有无virtual关键字修饰,有的话只是可以被重写而已),在构建了子类对象后,无论是将其转换为基类对象、还是赋值给基类对象,调用该基类对象并执行的都是基类中的方法(基类方法的引用地址未被修改)
    public override void IMethodForOverride() { Console.WriteLine("Override Method of Manager"); }
    //此处override,在构建子类对象后,若将其转换为基类对象、或是赋值给基类对象,调用该基类对象并执行的都是子类中的方法(基类方法的引用地址已被修改)
}

class TestHiding
{
    static void Main()
    {
        Manager m1 = new Manager();
        // Derived class property.
        m1.FirstName = "John";
        m1.LastName = "Lily";
        m1.IMethod();
        m1.IMethodForNew();
        m1.IMethodForOverride();
        // Base class property.
        ((Employee)m1).FirstName = "Mary";
        ((Employee)m1).IMethod();
        ((Employee)m1).IMethodForNew();
        ((Employee)m1).IMethodForOverride();
        Console.WriteLine(((Employee)m1).FirstName);
        Employee m2 = m1;
        m2.FirstName = "hhh";
        m2.IMethod();
        m2.IMethodForNew();
        m2.IMethodForOverride();
        Console.WriteLine(m2.FirstName);
        Employee m3 = new Employee();
        m3.IMethod();
        m3.IMethodForNew();
        m3.IMethodForOverride();
        System.Console.WriteLine("Name in the derived class is: {0}", m1.FirstName);
        System.Console.WriteLine("Name in the base class is: {0}-{1}", ((Employee)m1).FirstName,m2.FirstName);
    }
}

代码分析:    

    通过以上代码,对new和override关键字使用的总结如下:

    首先有一个派生类对象(m1),它是对由派生类构造函数创建的实例的引用,使用的属性、方法(无论是new还是override)都是派生类中的属性、方法。

    将该派生类对象(m1)隐式转换为基类对象((Employee)m1)后,产生了区别:

①再次调用被new过的属性和方法,都是基类中的属性和方法;

②再次调用被override过的属性和方法,都还是派生中的属性和方法;

    或者将派生类对象(m1)直接赋值给基类对象(m2)后(实际和隐式转换相同),同上。

执行结果如下:

原因:

    我们都知道,在new一个派生类对象前,总是要先调用基类对象的默认构造函数。

    如上图所示:被new过的FirstName属性分为在基类中的(有Generic.Employee后缀)和在派生类中的(无后缀),但在对该属性get、set时仅对派生类中该属性的引用进行操作;对于被new的IMethod和IMethodForNew调用亦然。

而在改对象被转换为基类对象后,原基类对象中被new的属性和方法都会被“暴露”出来(派生类对象只是隐藏但并未修改基类中属性和方法的引用地址);而被override的属性和方法都仍是派生类中的属性和方法(即其对基类中属性和方法的引用地址进行了修改(重写))。

注意:

仍可在派生类中通过实现操作“base.FirstName”属性的方法来实现对基类被new隐藏掉的属性的get或set。代码如下:

public class Manager : Employee
{
    //...重点突出以下代码,上文重复代码不再赘述
    public void SetBaseName(string s)
    {
        base.FirstName = s;
        Console.WriteLine("Base's FirstName property is set.");
    }
    public string GetBaseName()
    {
        Console.WriteLine($"Base's FirstName property is {base.FirstName} .");
        return base.FirstName;
    }
}
class TestHiding
{
    static void Main()
    {
        Manager m1 = new Manager();
        // Derived class property.
        m1.FirstName = "John";
        m1.LastName = "Lily";
        m1.IMethod();
        m1.IMethodForNew();
        m1.IMethodForOverride();


        //仍可通过子类去设置父类被隐藏的属性
        m1.SetBaseName(m1.LastName);
        m1.GetBaseName();

        //...
    }
}

输出结果如下:

结语:

    是否对new和override有了更深刻的理解呢,上文如有错误,烦请指出,谢谢!

猜你喜欢

转载自blog.csdn.net/qq_23958061/article/details/110236867