黑马程序员-.NET基础之继承和多态

来源:互联网 发布:数据库表的主键和外键 编辑:程序博客网 时间:2024/05/23 14:53

------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------

 

封装、继承、多态作为面向对象思想的三大核心思想,作为初学者,了解它们初步的特性,并能写出简单的示例代码,是我们必须要掌握的。可能有人会说,封装也是面向对象思想的三大核心思想之一啊,你为什么不讲讲,其实,当我在创建一个自定义的类时,就已经在进行封装了,所以我觉得稍微有点基础的人,应该都懂。好了,废话不多说,现将自己整理好的笔记供大家参考。

 

一、继承和多态的概念

继承允许重用现有类(基类,亦称超类、父类)去创建新类(子类,亦称派生类)的过程。子类将获取基类的所有非私有数据和行为,子类可以定义其他数据或行为派生类具有基类的所有非私有数据和行为以及新类自己定义的所有其他数据或行为,即子类具有两个有效类型:子类的类型和它继承的基类的类型对象可以表示多个类型的能力称为多态性。下面是一个多态性示例。

using System;namespace CSharpPractice.Polymorphism{    public class SimpleClassA    {        public SimpleClassA() { }        public void MethodA()        {            Console.WriteLine("调用MethodA()");        }    }    public class SimpleClassB : SimpleClassA    {        public SimpleClassB() { }        public void MethodB()        {            Console.WriteLine("调用MethodB()");        }    }    class Test    {        static void Main()        {            SimpleClassA oSimpleClassA = new SimpleClassA();            oSimpleClassA.MethodA(); //OK 调用类型SimpleClassA的成员方法            //SimpleClassB oSimpleClassB1 = (SimpleClassB)oSimpleClassA;//运行错误            SimpleClassB oSimpleClassB = new SimpleClassB();            oSimpleClassB.MethodB(); //OK 调用类型SimpleClassB的成员方法            oSimpleClassB.MethodA();// OK 调用基类SimpleClassA的成员方法            SimpleClassA oSimpleClassA1 = (SimpleClassA)oSimpleClassB;            oSimpleClassA1.MethodA();            //oSimpleClassA1.MethodB(); //编译错误 类型SimpleClassA不存在方法MethodB()            Console.ReadLine();            SimpleClassB oSimpleClassB1 = (SimpleClassB)oSimpleClassA1;            oSimpleClassB1.MethodB(); //OK 调用类型SimpleClassB的成员方法            oSimpleClassB1.MethodA();// OK 调用基类SimpleClassA的成员方法            Console.ReadKey();        }    }}

 

二、派生类

在声明派生类时,在类名称后放置一个冒号,然后在冒号后指定要从中继承的类(即基类)。派生类可以访问基类的非private成员,但是派生类的属性和方法不能直接访问基类的private成员。派生类可以影响基类private 成员的状态改变,但只能通过基类提供并由派生类继承的非private 的属性和方法来改变,C#不支持多重继承,即一个派生类只能继承于一个基类。派生类示例:创建基类Person,包含2个数据成员name和age、1个具有2个参数的构造函数;创建派生类Student,包含1个数据成员studentID、1个具有3个参数的派生类构造函数并用“:base”调用基类构造函数。

using System;namespace CSharpPractice.DerivedClass{    public class Person  //基类 等同于public class Person:Object      {        public string name;        public uint age;        public Person(string name, uint age) //基类的构造函数        {            this.name = name;            this.age = age;        }    }    public class Student : Person  //派生类    {        public string studentID;        //派生类构造函数并用“:base”调用基类构造函数        public Student(string name, uint age, string id)            : base(name, age)        {            this.studentID = id;        }    }    public class TestPersonStudent    {        static void Main(string[] args)        {            //构造             Student objstudent = new Student("Zhangsan", 25, "2008101001");            Console.WriteLine("name={0},  age={1},  ID={2}", objstudent.name, objstudent.age, objstudent.studentID);            Console.ReadLine();        }    }}

 

2.访问关键字this和base

this关键字引用类的当前实例。静态成员方法中不能使用this关键字。this关键字只能在实例构造函数、实例方法或实例访问器中使用
base关键字用于从派生类中访问基类的成员:
指定创建派生类实例时应调用的基类构造函数
调用基类上已被其他方法重写的方法
不能从静态方法中使用 base 关键字,base关键字只能在实例构造函数、实例方法或实例访问器中使用。

using System;namespace CSharpPractice.ThisBase{    public class Person  //基类 等同于public class Person:Object      {        public string name;        public uint age;        public Person(string name, uint age) //基类的构造函数        {            this.name = name; //this关键字引用类的当前实例            this.age = age;  //this关键字引用类的当前实例          }        public virtual void GetInfo()        {            Console.WriteLine("Name: {0}", name);            Console.WriteLine("Age: {0}", age);        }    }    public class Student : Person  //派生类    {        public string studentID;        //派生类构造函数并用“:base”调用基类构造函数         public Student(string name, uint age, string id)            : base(name, age)        {            this.studentID = id;        }        public override void GetInfo()        {            //调用基类的方法            base.GetInfo();            Console.WriteLine("StudentID: {0}", studentID);        }    }    public class TestPersonStudent    {        static void Main(string[] args)        {            //构造             Student objstudent = new Student("Zhangsan", 25, "2008101001");            objstudent.GetInfo();            Console.ReadLine();        }    }}

3.虚方法、重写方法和隐藏方法

在基类中使用关键字virtual定义虚方法(virtual method);然后派生类中使用关键字override来重写方法(override method),或使用关键字new来覆盖方法(隐藏方法)。重写方法用相同的签名重写所继承的虚方法。虚方法声明用于引入新方法,而重写方法或隐藏方法声明则用于使现有的继承虚方法专用化(通过提供该方法的新实现)。调用虚方法时,将首先检查该对象的运行时类型,并调用派生类中的该重写成员,如果没有派生类重写该成员,则调用其原始成员。默认情况下,C#方法是非虚拟的。不能重写非虚方法。除了类方法,还可以使用virtual关键字修饰的其他类成员以定义虚成员,包括:属性、索引器或事件声明。虚拟成员的实现可在派生类中使用关键字override来重写;或使用关键字new来覆盖。

using System;namespace CSharpPractice.Virtual{    class TestClass    {        public class Dimensions  //基类        {            public const double PI = Math.PI;            protected double x, y;            public Dimensions()            {            }            public Dimensions(double x, double y)            {                this.x = x;                this.y = y;            }            public virtual double Area()            {                return x * y;            }        }        public class Circle : Dimensions //派生类:圆        {            public Circle(double r)                : base(r, 0)            {            }            public override double Area()            {  //圆的面积                return PI * x * x;            }        }        class Sphere : Dimensions  //派生类:球体        {            public Sphere(double r)                : base(r, 0)            {            }            public override double Area()            {  // 球体表面积                return 4 * PI * x * x;            }        }        class Cylinder : Dimensions  //派生类:圆柱体        {            public Cylinder(double r, double h)                : base(r, h)            {            }            public override double Area()            {  //圆柱体表面积                return 2 * PI * x * x + 2 * PI * x * y;            }        }        static void Main()        {            double r = 3.0, h = 5.0;            Dimensions c = new Circle(r);      //圆            Dimensions s = new Sphere(r);      //球体            Dimensions l = new Cylinder(r, h); //圆柱体            // 显示各种不同形状的(表)面积:            Console.WriteLine("Area of Circle   = {0:F2}", c.Area());            Console.WriteLine("Area of Sphere   = {0:F2}", s.Area());            Console.WriteLine("Area of Cylinder = {0:F2}", l.Area());            Console.ReadKey();        }    }}

 

三、抽象类和抽象方法


将关键字 abstract 置于关键字 class 的前面可以将类声明为抽象类。抽象类不能实例化,抽象类一般用于提供多个派生类可共享的基类的公共定义。例如,类库可以定义一个包含基本功能的抽象类,并要求程序员使用该库通过创建派生类来提供自己的类实现。抽象类与非抽象类相比,具有下列特征:
1.抽象类不能直接实例化,对抽象类使用new运算符会导致编译时错误。可以定义抽象类型的变量,但其值必须为 null,或者是其派生的非抽象类的实例的引用
2.允许(但不要求)抽象类包含抽象成员
3.抽象类不能被密封
4.当从抽象类派生非抽象类时,这些非抽象类必须实现所继承的所有抽象成员,从而重写那些抽象成员

using System;namespace CSharpPractice.Abstract{    abstract class Animal   // 基类Animal:抽象类    {        public abstract void SayHello();    }    class Dog : Animal     // 派生类Dog    {        public override void SayHello()        {   //重写SayHello()            Console.WriteLine("Wow Wow!");        }    }    class Cat : Animal     // 派生类Cat    {        public override void SayHello()        {   //重写SayHello()            Console.WriteLine("Mew Mew!");        }    }    class TestClass    {        static void Main()        {            Animal[] animals =        {            new Dog(),            new Cat()        };            foreach (Animal a in animals)            {                a.SayHello();            }            Console.ReadKey();        }    }}

 

四、接口

一个接口定义一个协定。接口本身不提供它所定义的成员的实现,接口只指定实现该接口的类或结构必须提供的成员,继承接口的任何非抽象类型都必须实现接口的所有成员。接口类似于抽象基类,接口不能实例化。接口中声明的所有成员隐式地为public和abstract。接口可以包含事件、索引器、方法和属性,但接口不能包含字段。下面给出两个接口实现示例。

using System;namespace CSharpPractice.Interface{    public interface IBankAccount  // 银行账户    {        void PayIn(decimal amount);      // 存款        bool Withdraw(decimal amount);   // 取款,并返回是否成功        decimal Balance                // 余额        {            get;        }    }    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;            }            Console.WriteLine("余额不足,取款失败!");            return false;        }        public decimal Balance        {   // 返回余额            get            {                return balance;            }        }        public bool TransferTo(IBankAccount destination, decimal amount)        {   // 银行转账            bool result;            if ((result = Withdraw(amount)) == true)                destination.PayIn(amount);            return result;        }        public override string ToString()        {   // 返回银行当前账户中的余额            return String.Format("Jupiter Bank Current Account: Balance = {0,6:C}", balance);        }    }    class TestClass    {        static void Main()        {   // 当前账户            IBankAccount venusAccount = new CurrentAccount();            // 转账账户            ITransferBankAccount jupiterAccount = new CurrentAccount();            // 当前账户存款            venusAccount.PayIn(200);            // 转账到转账账户            jupiterAccount.PayIn(500);            // 转账账户再转账到当前账户            jupiterAccount.TransferTo(venusAccount, 100);            // 显示账户余额            Console.WriteLine(venusAccount.ToString());            Console.WriteLine(jupiterAccount.ToString());            Console.ReadLine();        }    }}

好了,关于继承和多态的笔记就写到这里吧。
 

------- Windows Phone 7手机开发、.Net培训、期待与您交流! -------

0 0
原创粉丝点击