现在的位置: 首页 > 综合 > 正文

关于C#面向对象三个特征:继承,封装,多态的说明

2011年11月16日 ⁄ 综合 ⁄ 共 11573字 ⁄ 字号 评论关闭
下面重点说明面向对象的三个特征.继承,封装和多态.
C#是一种现代的面向对象的语言.
继承(inheritance):继承是一个面向对象的词语.说明,一个类(派生类)能分享,其它类(基类)的特征和行为.派

生类和基类是"is a"的关系.
base classes(基类):通常基类可以自己实例化,或被继承.派生类继承基类中的成员,被标记为protected或更大

的权限.语法: class (derive class name):(base class name)
例子:
//基类
public class Contact
{
  //默认私有的字段
  string name;
  string email;
  string address;
  //构造函数
  public Contact()
  {
    // statements ...
  }
  //属性
  public string Name
  {
    get
    {
      return name;
    }
    set
    {
      name = value;
    }
  }

  public string Email
  {
    get
    {
      return email;
    }
    set
    {
      email = value;
    }
  }

  public string Address
  {
    get
    {
      return address;
    }
    set
    {
      address = value;
    }
  }
}
//派生类
public class Customer : Contact
{
  //自己的私有字段
  string gender;
  decimal income;

  public Customer()
  {
    // statements ...
  }
}
在上面的例子中,Customer 是

Contact的子类,不但,继承了父类的成员,name,email,address;还有自己的成员,gender,income.

abstract classes(抽象类):抽象类是一种特殊的基类.除过普通的类成员,它们还有抽象的类成员.抽象类成员,

是不能被实例化的方法和属性.所有直接从抽象类派生的类,必须实现抽象的方法和属性.抽象类不能被实例化.
例子:
//抽象类
abstract public class Contact
{
  protected string name;

  public Contact()
  {
    // statements...
  }

  //抽象方法
  public abstract void generateReport();
  //抽象属性
  abstract public string Name
  {
    get;
    set;
  }}

public class Customer : Contact
{
  string gender;
  decimal income;
  int numberOfVisits;

  public Customer()
  {
    // statements
  }

  public override void generateReport()
  {
    // unique report
  }

  public override string Name
  {
    get
    {
      numberOfVisits++;
      return name;
    }
    set
    {
      name = value;
      numberOfVisits = 0;
    }
  }
}

public class SiteOwner : Contact
{
  int siteHits;
  string mySite;

  public SiteOwner()
  {
    // statements...
  }

  public override void generateReport()
  {
    // unique report
  }

  public override string Name
  {
    get
    {
      siteHits++;
      return name;
    }
    set
    {
      name = value;
      siteHits = 0;
    }
  }
}
上面的例子,定义了三个类.一个抽象类,两个派生类.实现了父类的方法和属性."override"修饰符,实现了抽象

类的方法.    
Calling Base Class Members(调用基类成员)
派生类能调用基类成员,如果,成员的修饰符是"protected"或更大权限.在适当的上下文条件下,好像调用自己的

成员一样.
例子:
abstract public class Contact
{
  private string address;
  private string city;
  private string state;
  private string zip;

  public string FullAddress()
  {
    string fullAddress =
      address + ''\n'' +
      city + '','' + state + '' '' + zip;

    return fullAddress;
  }
}

public class Customer : Contact
{
  public string GenerateReport()
  {
    string fullAddress = FullAddress();
    // do some other stuff...
    return fullAddress;
  }
}
上面的例子中,派生类调用基类的方法:FullAddress();
基类的构造函数,可以被派生类调用,用base().
例子:
abstract public class Contact
{
  private string address;

  public Contact(string address)
  {
    this.address = address;
  }
}

public class Customer : Contact
{
  public Customer(string address) : base(address)
  {
  }
}
例子中,派生类没有address成员,可以调用基类的构造函数.
Hiding Base Class Members(隐藏基类成员)
派生类可以和基类有同样名字的成员.这时,就会隐藏基类的成员.
例子:
abstract public class Contact
{
  private string address;
  private string city;
  private string state;
  private string zip;

  public string FullAddress()
  {
    string fullAddress =
      address + ''\n'' +
      city + '','' + state + '' '' + zip;

    return fullAddress;
  }
}

public class SiteOwner : Contact
{
  public string FullAddress()
  {
    string fullAddress;

    // create an address...
    return fullAddress;
  }
}
在例子中,派生类和基类有同样的成员,FullAddress(),当调用时,基类的方法会被隐藏.

尽管基类的成员被隐藏,仍然可以访问基类的成员,通过,base关键字,调用基类的引用.
例子:
abstract public class Contact
{
  private string address;
  private string city;
  private string state;
  private string zip;

  public string FullAddress()
  {
    string fullAddress =
      address + ''\n'' +
      city + '','' + state + '' '' + zip;

    return fullAddress;
  }
}

public class SiteOwner : Contact
{
  public string FullAddress()
  {
    string fullAddress = base.FullAddress();

    // do some other stuff...
    return fullAddress;
  }
}
在例子中,派生类调用基类的成员,用base引用.
visioning(版本)
例子:
using System;
public class WebSite
{
  public string SiteName;
  public string URL;
  public string Description;

  public WebSite()
  {
  }

  public WebSite( string strSiteName, string strURL, string strDescription )
  {
    SiteName  = strSiteName;
    URL     = strURL;
    Description = strDescription;
  }

  public override string ToString()
  {
    return SiteName + ", " +
        URL   + ", " +
        Description;
  }
}

public class Contact
{
  public string address;
  public string city;
  public string state;
  public string zip;

  public string FullAddress()
  {
    string fullAddress =
      address + ''\n'' +
      city + '','' + state + '' '' + zip;

    return fullAddress;
  }
}

public class SiteOwner : Contact
{
  int   siteHits;
  string name;
  WebSite mySite;

  public SiteOwner()
  {
    mySite = new WebSite();
    siteHits = 0;
  }

  public SiteOwner(string aName, WebSite aSite)
  {
    mySite = new WebSite(aSite.SiteName,
               aSite.URL,
               aSite.Description);

    Name = aName;
  }

  new public string FullAddress()
  {
    string fullAddress = mySite.ToString();

    return fullAddress;
  }

  public string Name
  {
    get
    {
      siteHits++;
      return name;
    }
    set
    {
      name = value;
      siteHits = 0;
    }
  }
}

public class Test
{
  public static void Main()
  {
    WebSite mySite = new WebSite("Le Financier",
                   "http://www.LeFinancier.com",
                   "Fancy Financial Site");

    SiteOwner anOwner = new SiteOwner("John Doe", mySite);
    string address;

    anOwner.address = "123 Lane Lane";
    anOwner.city  = "Some Town";
    anOwner.state  = "HI";
    anOwner.zip   = "45678";

    address = anOwner.FullAddress(); // Different Results
    Console.WriteLine("Address: \n{0}\n", address);

  }
}
例子中,派生类用new修饰符,说明,和基类有同样名字的成员.
sealed classed(密封类)
密封类是不能被继承的类.为了避免从一个类中继承,就要生成密封类.
例子:
//密封类
public sealed class CustomerStats
{
  string gender;
  decimal income;
  int numberOfVisits;

  public CustomerStats()
  {
  }
}

public class CustomerInfo : CustomerStats // error
{
}

public class Customer
{
  CustomerStats myStats; // okay
}
例子中,密封类不能被继承.

封装(Encapsulation):封装是一个面向对象的概念,对外部世界,隐藏类的内部.
封装优点:
1.好的封装能减少耦合.
2.类的内部的实现可以自由改变.
3.一个类有更清楚的接口.
Data Hiding(数据隐藏):封装的一个最有用的形式是数据隐藏.一个类的数据表现一个对象的状态.
修饰符支持封装:
Private:只有类本身能存取.
Protected:类和派生类可以存取.
Internal:只有同一个项目中的类可以存取.
Protected Internal:是Protected和Internal的结合.
Public:完全存取.
other Encapsulating Strategy:(其他封装策略)属性和索引器的目的是封装一个类的细节和给类的用户提供一个公共的接口.
封装和继承的关系:
封装的意思是包容(聚合),类与类之间的关系是"has a".一个类里面有另一个类.
继承,类与类之间的关系是"is a".

多态(Polymorphism):就是怎样重载一个虚拟类.多态是面向对象的重要概念.
Implementing Polymorphism(实现多态):
例子:
using System;
public class WebSite
{
  public string SiteName;
  public string URL;
  public string Description;

  public WebSite()
  {
  }

  public WebSite( string strSiteName, string strURL, string strDescription )
  {
    SiteName  = strSiteName;
    URL     = strURL;
    Description = strDescription;
  }

  public override string ToString()
  {
    return SiteName + ", " +
        URL   + ", " +
        Description;
  }
}

abstract public class Contact
{
  public virtual string UpdateNotify()
  {
    return "Web Site Change Notification";
  }
}

public class Customer : Contact
{
  public new string UpdateNotify()
  {
    return @"
This is to let you know your
favorite site, Financial Times,
has been updated with new links";
  }
}

public class SiteOwner : Contact
{
  WebSite mySite;

  public SiteOwner(string aName, WebSite aSite)
  {
    mySite = new WebSite(aSite.SiteName,
               aSite.URL,
               aSite.Description);
  }

  public new string UpdateNotify()
  {
    return @"
This is to let you know your site, " + "\n" +
mySite.SiteName + @", has been added as
a link to Financial Times.";
  }
}

public class Test
{
  public static void Main()
  {
    WebSite leFin = new WebSite("Le Financier",
                  "http://www.LeFinancier.com",
                  "Fancy Financial Site");

    Contact[] Contacts = new Contact[2];

    Contacts[0] = new SiteOwner("Pierre Doe", leFin);
    Contacts[1] = new Customer();

    foreach (Contact poc in Contacts)
    {
      if (poc is SiteOwner)
      {
        Console.WriteLine("Message: {0}\n",
         ((SiteOwner)poc).UpdateNotify());
      }
      else
      {
        Console.WriteLine("Message: {0}\n",
         ((Customer)poc).UpdateNotify());
      }
    }
  }
}
在例子中,Contact类有个虚拟方法,有两个派生类分别实现.使用了"new"关键字.
可以有更有效和优雅的方法,实现它,就是多态.
例子:
using System;
abstract public class Contact
{
  public virtual string UpdateNotify()
  {
    return "Web Site Change Notification";
  }
}

public class Customer : Contact
{
  public override string UpdateNotify()
  {
    return @"
This is to let you know your
favorite site, Financial Times,
has been updated with new links";
  }
}

public class SiteOwner : Contact
{
  string siteName;

  public SiteOwner(string sName)
  {
    siteName = sName;
  }

  public override string UpdateNotify()
  {
    return @"
This is to let you know your site, " + "\n" +
siteName + @", has been added as
a link to Financial Times.";
  }
}
public class Test
{
  public static void Main()
  {
    Contact[] Contacts = new Contact[2];

    Contacts[0] = new SiteOwner("Le Financier");
    Contacts[1] = new Customer();

    foreach (Contact poc in Contacts)
    {
      Console.WriteLine("Message: {0}\n",
               poc.UpdateNotify());
    }
  }
}

例子中,派生类用"override"实现了多态.
虚拟方法是允许多态工作的基类的方法.用"override"修饰符说明,能被派生类重载.虚拟方法和抽象方法的不同

时,虚拟方法有实现,抽象方法没有.抽象方法,隐式说明是虚拟,必须被重载;虚拟方法不必被重载.

多态,必须是虚拟方法,而且,方法的签名必须一致,包括方法名称,参数,和参数类型.
例子:
abstract public class Contact
{
  public virtual string UpdateNotify()
  {
    return "Web Site Change Notification";
  }
}

public class Customer : Contact
{
  public override string SendMail() {}// error

  public override string UpdateNotify(int number) {}// error
}
例子中,SendMail不是虚拟方法,故错误;UpdateNotify,带有不同的参数,故也错误.

new 和 override 修饰符,都可以实现新的方法.但,new 实现的是派生类新的方法.
例子:
using System;

abstract public class Contact
{
  public virtual string UpdateNotify()
  {
    return "Web Site Change Notification";
  }
}

public class Customer : Contact
{
  public new string UpdateNotify()
  {
    return @"
This is to let you know your
favorite site, Financial Times,
has been updated with new links";
  }
}

public class SiteOwner : Contact
{
  string siteName;

  public SiteOwner(string sName)
  {
    siteName = sName;
  }

  public override string UpdateNotify()
  {
    return @"
This is to let you know your site, " + "\n" +
siteName + @", has been added as
a link to Financial Times.";
  }
}

public class Test
{
  public static void Main()
  {
    Contact[] Contacts = new Contact[2];

    Contacts[0] = new SiteOwner("Le Financier");
    Contacts[1] = new Customer();

    foreach (Contact poc in Contacts)
    {
      Console.WriteLine("Message: {0}\n",
               poc.UpdateNotify());
    }
  }
}
结果是:
Message:
This is to let you know your site,
Le Financier, has been added as
a link to Financial Times.

Message: Web Site Change Notification
例子中,Customer 用"new"实现新的方法,但是,在运行是不是多态.仍然调用基类的方法.

Most-Derived Implementations(多重派生实现)

Polymorphic Properties(多态的属性):C#允许,属性的多态实现.
例子:
using System;

public class SiteStats
{
  public int numberOfVisits = 0;
}

abstract public class Contact
{
  protected string name;

  public virtual string Name
  {
    get
    {
      return name;
    }
    set
    {
      name = value;
    }
  }
}

public class Customer : Contact
{
  SiteStats myStats = new SiteStats();

  public override string Name
  {
    get
    {
      myStats.numberOfVisits++;
      Console.WriteLine("Number of visits: {0}",
               myStats.numberOfVisits);

      return name;
    }
    set
    {
      base.Name = value;
      myStats.numberOfVisits = 0;
      Console.WriteLine("Name: {0}", Name);
    }
  }
}

public class Test
{
  public static void Main()
  {
    Contact myContact = new Customer();
    myContact.Name = "George";
  }
}
例子中,抽象类,有属性Name,派生类重载实现了属性.

Polymorphic Indexers(多态的索引器):索引器的多态.
例子:
using System;
using System.Collections;
public class SiteList
{
  protected SortedList sites;

  public SiteList()
  {
    sites = new SortedList();
  }

  public int NextIndex
  {
    get {
      return sites.Count;
    }
  }

  public virtual string this[int index]
  {
    get
    {
      return (string) sites.GetByIndex(index);
    }
    set
    {
      sites[index] = value;
    }
  }
}

public class FinancialSiteList : SiteList
{
  public override string this[int index]
  {
    get
    {
      Console.WriteLine("FinancialSiteList Indexer Get");
      if (index > sites.Count)
        return (string)null;

      return base[index];
    }
    set
    {
      Console.WriteLine("FinancialSiteList Indexer Set");
      base[index] = value;
    }
  }
}

class SiteManager
{
  SiteList sites = new SiteList();

  public static void Main()
  {
    SiteManager mgr = new SiteManager();

    mgr.sites = new FinancialSiteList();

    mgr.sites[mgr.sites.NextIndex] = "Great Site!";

    Console.WriteLine("Site: {0}",
      mgr.sites[0].ToString());
  }
}
例子中,基类的索引器是"virtual",派生类重载了索引器.

抱歉!评论已关闭.