zoukankan      html  css  js  c++  java
  • 第4章 继承

    1. 继承的类型

    • C#类可以派生自另一个类和任意多个接口。
    • 结构总派生自System.ValueType,故不支持实现继承,但支持接口继承,即可以派生自任意多个接口。
    • 类总派生自System.Object或用户选择的另一个类,还可以派生自任意多个接口。
    • 如果类和接口都用于派生,则类总是必须放在接口的前面。

    2.实现继承

    (1) 虚方法:

    • 基类方法或属性声明命名为virtual,任何派生类中使用override显示声明来重写该方法或属性。
    • 成员字段和静态函数不能声明为virtual,因为虚方法只对类中的实例函数成员有意义。

    (2) 多态性:

    • 方法中接收基类作为参数,则任何派生自基类的类型都可以传递给该方法。
    • 方法中使用参数的方法,如不是虚拟参数或没有重写派生类的方法,则执行基类方法;否则执行派生类方法。

    (3) 隐藏方法:(尽量不使用)

    • 若签名相同的方法,在基类和派生类中都进行了声明,但该方法没有分别声明为virtual和override,派生类方法就会隐藏基类方法。
    • 使用new关键字隐藏方法,避免出现编译警告,用于处理版本冲突。

    (4) 调用方法的基类版本:使用base关键字,在派生类中调用基类方法。

    (5) 抽象类和抽象方法:

    • 类和方法可以使用abstract关键字声明为抽象类和抽象方法。
    • 类中包括抽象方法,则该类也必须声明为抽象类。
    • 抽象类不能实例化;抽象方法不能直接实现,必须在非抽象的派生类中重写(关键字override);派生类中需要实现所有抽象成员。
    • 虽然抽象类不能实例化,但可以声明一个抽象类变量,由实例化的派生类将其分配给基类。
    // 抽象基类 Shape
    public abstract class Shape
    {
          public abstract void Resize(int width, int height); //抽象方法
    }
     
    // 派生类 Ellipse
    public class Ellipse : Shape
    {
          public override void Resize(int width, int height)
          {
                Size.Width = width;
                Size.Height = height;
          }
    }
     
    //实例化
    Shape s1 = new Ellipse();

     (6) 密封类和密封方法:sealed修饰符

    • 密封类表示不允许创建该类的子类。
    • 密封方法表示不能重写该方法。
    • 常用密封方法来终止继承:方法可以是基类的重写方法,但其继承类中不能扩展该方法。
    class MyClass: MyBaseClass
    {
         public sealed override void FinalMethod()
         {
              // implementation
         }
    }
    
    class DerivedClass: MyClass
    {
         public override void FinalMethod()   //wrong!Will give compilation error
         {
         }
    }

     (7) 派生类的构造函数:

    • 对于派生类,需保证通过层次结构进行构造。
    • 构造函数总是按照层次结构的顺序调用:先调用System.Object类的构造函数 -> 再按照层次结构由上向下进行 -> 直到到达编译器要实例化的类为止。
    // 使用自动属性初始化器初始化属性
    // 编译器会创建一个默认的构造函数
    public class Sharp
    {
            public Position Position { get; } = new Position();
            public Size Size { get; } = new Size();
    }
    
    // 派生类Ellipse
    public class Ellipse : Sharp
    {
           public Ellipse()
                  : base()
           {
           }
    }
    
    // 实例化Ellipse类,构造函数调用顺序为
    // Object 构造函数 -> Sharp 构造函数 -> Ellipse 构造函数
    •  使用构造函数初始化器调用带参数的基类构造函数的赋值方式
    // 基类构造函数内进行赋值,非默认初始化
    public class Shape
    {
            public Shape(int width, int height, int x, int y)
            {
                Size = new Size { Width = width, Height = height };
                Position = new Position { X = x, Y = y };
            }
    }
    
    //  派生类
    public class Ellipse : Shape
    {
            // 派生类中创建构造函数,用构造函数初始化器初始化基类的构造函数
            public Ellipse(int width, int height, int x, int y)
                : base(width, height, x, y)
            {
    
            }
            // 希望允许使用默认的构造函数创建Ellipse对象
            public Ellipse()
                : base( 0, height: 0, x: 0, y: 0)
            {
    
            }
    }

     3. 接口:interface

    • 接口只包括方法、属性、索引器和事件的声明。
    • 不允许提供接口中任何成员的实现方式。
    • 比较接口和抽象类:

    (1) 定义和实现接口

    • 接口的命名采用Hungarian表示法,即在名称前加一个字母,表示所定义对象的类型。接口类型字母为I。
        public interface IBankAccount
        {
            void PayIn(decimal amount);
            bool Withdraw(decimal amount);
            decimal Balance { get; }
        }
        // 派生类 SaverAccount
        public class SaverAccount : IBankAccount
        {
            private decimal _balance;
    
            public void PayIn(decimal amount) => _balance += amount;
    
            public bool Withdraw(decimal amount)
            {
                if (_balance >= amount)
                {
                    _balance -= amount;
                    return true;
                }
                WriteLine("Withdrawal attempt failed.");
                return false;
            }
    
            public decimal Balance => _balance;
    
            public override string ToString() =>
                $"Venus Bank Saver: Balance = {_balance,6:C}";
        }
    
    
        // 派生类  GoldAccount
        public class GoldAccount : IBankAccount
        {
             //etc
        }
    • 接口仅表示其成员的存在性,派生的类负责确定这些成员是虚拟还是抽象的(但只有在类本身是抽象的,这些函数才能是抽象的)。
    • 接口引用安全可以按成类引用——但接口引用强大之处在于,它可以引用任何实现该接口的类。
    IBankAccount[] accounts = new IBankAccount[2];
    account[0] = new SaverAccount();
    account[1] = new GoldAccount();

     (2) 派生的接口

    • 接口可以彼此派生,实现派生接口的类必须实现相关接口的所有方法。
        public interface ITransferBankAccount : IBankAccount
        {
            bool TransferTo(IBankAccount destination, decimal amount);
        }
       public class CurrentAccount : ITransferBankAccount
        {
            private decimal _balance;
    
            public void PayIn(decimal amount) => _balance += amount;
    
            public bool Withdraw(decimal amount)
            {
                if (_balance >= amount)
                {
                    _balance -= amount;
                    return true;
                }
                WriteLine("Withdrawal attempt failed.");
                return false;
            }
    
            public decimal Balance => _balance;
    
            public bool TransferTo(IBankAccount destination, decimal amount)
            {
                bool result = Withdraw(amount);
                if (result)
                {
                    destination.PayIn(amount);
                }
                return result;
            }
    
            public override string ToString() =>
              $"Jupiter Bank Current Account: Balance = {_balance,6:C}";
        }
    • 在实现并调用派生接口的方法时,不必知道该对象类型,只需要知道该对象实现了接口即可。

    4. is 和 as 运算符: 与继承有关

    • as运算符:返回对象的引用,且不抛出InvalidCastException异常;如不是所需要类型,返回null。
    public void WorkWithManyDifferentObject(object o)
    {
        IBankAccount account = o as IBankAccount;
        if (account != null)
        {
              //work with the account
        }
    }
    •  is运算符:根据对象是否使用指定的类型,返回true或false。
    public void WorkWithManyDifferentObject(object o)
    {
        if (o is IBankAccount)
        {
              IBankAccount account = (IBankAccount)o;
              //work with the account
        }
    }

    注:文中代码均来自《C#高级编程(第10版)C# 6 & .NET Core 1.0》

  • 相关阅读:
    VIJOS-P1340 拯救ice-cream(广搜+优先级队列)
    uva 11754 Code Feat
    uva11426 GCD Extreme(II)
    uvalive 4119 Always an Interger
    POJ 1442 Black Box 优先队列
    2014上海网络赛 HDU 5053 the Sum of Cube
    uvalive 4795 Paperweight
    uvalive 4589 Asteroids
    uvalive 4973 Ardenia
    DP——数字游戏
  • 原文地址:https://www.cnblogs.com/zhangjbravo/p/9430434.html
Copyright © 2011-2022 走看看