探讨继承与实现(一)

PS:原文名《探讨C#的继承》 。经双鱼座的提醒,改名为探讨继承与实现。并把文章关于接口继承的描述改为实现。顺便把部分内容进行了改写,以使行文更加流畅,内容更加丰满。修改部分标识为蓝色。 2007年2月1日

2006年6月19日         By   谢平
http://www.cnblogs.com/birdshover/

继承是建立一个类,然后创建它的更特殊的版本。是OOP中不可缺少的部分。
人在描述事物的时候是有层次的,那么继承就使程序对现实世界有层次的描述的表达成为可能。对程序员来说继承的重点是共同点。因为有共同点才能重用。

实现是建立一个接口,然后由某些类来实现接口描述的细节。就好比是工程师绘制了部件,然后由工人做出具体的产品,工程师并没有去制造部件。

类与接口的区别就在于此,类不但有描绘,还实现了部分细节。而特殊的抽象类完全带抽象方法,就和接口完成的同样功用。而且,无论接口还是类,都不是凭空去描绘出来的 ,否则就是纸上谈兵了,而是根据具体类的特征抽象出来的。所以他们有共同点。


目录
一、继承与实现
      接口 实现示例
      类继承示例
二、继承 ,实现简单论述
      1、接口的实现以及接口对类的访问
      2、类的继承关于以及父类对子类的访问

一、继承与实现
          抽象有两种抽象方式。
         1、他们有相同的工作方式;
         2、他们有相同的名称、作用和特征。
          第一种方式是类的继承,而第二种方式是接口的实现。

         比如:数据库操作中一般都会用到 添加,删除,更新,读取。那么就是他们都有相同的名称、作用和特征。就可以使用接口实现。

None.gif using  System.Collections;
None.gif
using  System.Data;
None.gif
None.gif
interface  IMyData
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
void MyInsert(ArrayList al);
InBlock.gif    
void MyDelete(ArrayList al);
InBlock.gif    
void MyUpdate(ArrayList al);
InBlock.gif    DataSet MySelect(ArrayList al);
ExpandedBlockEnd.gif}

None.gif using  System;
None.gif
None.gif
namespace  FmRadio
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// DMusicSort 的摘要说明。
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public class DMusicSort : IMyData
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
public DMusicSort()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// TODO: 在此处添加构造函数逻辑
InBlock.gif            
//
ExpandedSubBlockEnd.gif
        }

ContractedSubBlock.gifExpandedSubBlockStart.gif        
IMyData 成员#region IMyData 成员
InBlock.gif
InBlock.gif        
public void MyInsert(System.Collections.ArrayList al)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// TODO:  添加 DMusicSort.MyInsert 实现
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        
public void MyDelete(System.Collections.ArrayList al)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// TODO:  添加 DMusicSort.MyDelete 实现
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        
public void MyUpdate(System.Collections.ArrayList al)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// TODO:  添加 DMusicSort.MyUpdate 实现
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        
public System.Data.DataSet MySelect(System.Collections.ArrayList al)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// TODO:  添加 DMusicSort.MySelect 实现
InBlock.gif
            return null;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

再比如:数据库的连接,这里只说MS Sql Srever 2000,在一个程序只使用一个库的情况下,所有关于数据库操作类都将执行相同的数据库连接。他们有相同的工作方式。

None.gif using  System;
None.gif
using  System.Data;
None.gif
using  System.Data.SqlClient;
None.gif
using  System.Configuration;
None.gif
None.gif
namespace  FmRadio
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// MyConnection 的摘要说明。
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public class MyConnection
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private SqlConnection pConn;
InBlock.gif
InBlock.gif        
public MyConnection()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// TODO: 在此处添加构造函数逻辑
InBlock.gif            
//
InBlock.gif
            pConn = new SqlConnection(ConfigurationSettings.AppSettings["DbLink"]);
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public SqlConnection conn
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
get
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
// TODO:  添加 MyConnection.conn getter 实现
InBlock.gif
                return pConn;
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif using  System;
None.gif
using  System.Data;
None.gif
using  System.Data.SqlClient;
None.gif
using  System.Collections;
None.gif
None.gif
namespace  FmRadio
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// Execute 的摘要说明。
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public class Execute : MyConnection
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
private int sType = 0;
InBlock.gif        
private ArrayList pPara;
InBlock.gif        
private string pContext;
InBlock.gif
InBlock.gif        
public Execute()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// TODO: 在此处添加构造函数逻辑
InBlock.gif            
//
ExpandedSubBlockEnd.gif
        }

InBlock.gif
InBlock.gif        
public Execute(string pContext,ArrayList pPara)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.pPara = pPara;
InBlock.gif            
this.pContext = pContext;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public Execute(int pType,string pContext,ArrayList pPara)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
this.sType = pType;
InBlock.gif            
this.pPara = pPara;
InBlock.gif            
this.pContext = pContext;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public int ExeNone()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// TODO:  添加 Execute.ExeNone 实现
InBlock.gif
            SqlCommand sc = null;
InBlock.gif            CommandType ct 
= CommandType.StoredProcedure;
InBlock.gif            
if(this.sType==0)
InBlock.gif                ct 
= CommandType.StoredProcedure;
InBlock.gif            
else
InBlock.gif                ct 
= CommandType.Text;
InBlock.gif
InBlock.gif            
int rs = 0;
InBlock.gif            sc 
= new SqlCommand();
InBlock.gif            sc.CommandType 
= ct;
InBlock.gif            sc.Connection 
= conn;
InBlock.gif            sc.CommandText 
= pContext;
InBlock.gif            
foreach(DataPara dp in pPara)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                sc.Parameters.Add(
"@" + dp.ColName,dp.ColContent.GetType()).Value = dp.ColContent;
ExpandedSubBlockEnd.gif            }

InBlock.gif
//            try
InBlock.gif
//            {
InBlock.gif
                conn.Open();
InBlock.gif                rs 
= sc.ExecuteNonQuery();
InBlock.gif                conn.Close();
InBlock.gif
//            }
InBlock.gif
//            catch{}
InBlock.gif
            return rs;
ExpandedSubBlockEnd.gif        }

InBlock.gif
InBlock.gif        
public DataSet ExeTable()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// TODO:  添加 Execute.ExeTable 实现
InBlock.gif
            SqlDataAdapter sda = new SqlDataAdapter();
InBlock.gif            SqlCommand sc 
= null;
InBlock.gif            CommandType ct 
= CommandType.StoredProcedure;
InBlock.gif            
if(this.sType==0)
InBlock.gif                ct 
= CommandType.StoredProcedure;
InBlock.gif            
else
InBlock.gif                ct 
= CommandType.Text;
InBlock.gif
InBlock.gif            sc 
= new SqlCommand();
InBlock.gif            sc.CommandType 
= ct;
InBlock.gif            sc.Connection 
= conn;
InBlock.gif            sc.CommandText 
= pContext;
InBlock.gif            
foreach(DataPara dp in pPara)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                sc.Parameters.Add(
"@" + dp.ColName,dp.ColContent.GetType()).Value = dp.ColContent;
ExpandedSubBlockEnd.gif            }

InBlock.gif            sda.SelectCommand 
= sc;
InBlock.gif            DataSet ds 
= new DataSet();
InBlock.gif
//            try
InBlock.gif
//            {
InBlock.gif
                conn.Open();
InBlock.gif                sda.Fill(ds,
"asdasd");
InBlock.gif                conn.Close();
InBlock.gif
//            }
InBlock.gif
//            catch{}
InBlock.gif
            return ds;
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

二、继承,实现简单论述
下面,我们找更加简单的例子来探讨继承和实现。

1、接口的实现以及接口对类的访问
None.gif interface  A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
void a();
ExpandedBlockEnd.gif}

None.gif using  System;
None.gif
None.gif
namespace  Mocl
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// A的摘要说明。
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    public class A : IA    
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
public A()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// TODO: 在此处添加构造函数逻辑
InBlock.gif            
//
ExpandedSubBlockEnd.gif
        }

ContractedSubBlock.gifExpandedSubBlockStart.gif        
IA 成员#region IA 成员
InBlock.gif
InBlock.gif        
public void a()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
// TODO:  添加 A.a 实现
InBlock.gif
            System.Diagnostics.Debug.WriteLine("a");
ExpandedSubBlockEnd.gif        }

InBlock.gif
ExpandedSubBlockEnd.gif        
#endregion

InBlock.gif
InBlock.gif        
public void b()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            System.Diagnostics.Debug.WriteLine(
"b");
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

执行以下方法
None.gif using  System;
None.gif
None.gif
namespace  Mocl
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// Class1 的摘要说明。
ExpandedSubBlockEnd.gif    
/// </summary>
InBlock.gif    class Class1
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 应用程序的主入口点。
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        [STAThread]
InBlock.gif        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// TODO: 在此处添加代码以启动应用程序
InBlock.gif

InBlock.gif            A a 
= new A();
InBlock.gif            a.a();
InBlock.gif            a.b();
InBlock.gif            IA c 
= new A();
InBlock.gif            c.a();
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif


输出
a
b
a

IA c = new A();通过接口访问类。注意使用IA c = new A();的时候,对象c是访问不到类A的方法成员void b()的。因为父类访问子类的时候只会返回父类所定义的方法成员的引用。

我们可以再给类A 添加个字段 public int i = 0;
A的方法a换成 
  public void a()
  {
   // TODO:  添加 A.a 实现
   System.Diagnostics.Debug.WriteLine("a"  + i.ToString());
  }

继续执行,发现输出
a0
b
a0
从这点上看出接口对子类的引用并不阻止类执行在访问过程中要使用到的成员,无论这些成员是否是接口的一部分。

2、类的继承关于以及父类对子类的访问
我是在网上看了类似的问题,才有兴趣对继承的各种关系进行学习。才有此文,和大家分享我的学习体会。所以这里就用他的原问题,进行探讨。

None.gif public   class  A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif 
public  void printA()
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  System.Diagnostics.Debug.WriteLine(
"printA");
ExpandedSubBlockEnd.gif }

InBlock.gif 
public virtual void valueA()
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  System.Diagnostics.Debug.WriteLine(
"ValueA");
ExpandedSubBlockEnd.gif }

ExpandedBlockEnd.gif}

None.gif
None.gif
public   class  B:A
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif 
new public void printA()
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  System.Diagnostics.Debug.WriteLine(
"printB");
ExpandedSubBlockEnd.gif }

InBlock.gif
InBlock.gif 
public override void valueA()
ExpandedSubBlockStart.gifContractedSubBlock.gif 
dot.gif{
InBlock.gif  System.Diagnostics.Debug.WriteLine(
"ValueB()");
ExpandedSubBlockEnd.gif }

ExpandedBlockEnd.gif}

None.gif

None.gif using  System;
None.gif
None.gif
namespace  Mocl
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
InBlock.gif    
/// Class1 的摘要说明。
ExpandedSubBlockEnd.gif    
/// </summary>
InBlock.gif    class Class1
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
InBlock.gif        
/// 应用程序的主入口点。
ExpandedSubBlockEnd.gif        
/// </summary>
InBlock.gif        [STAThread]
InBlock.gif        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            
//
InBlock.gif            
// TODO: 在此处添加代码以启动应用程序
InBlock.gif            
//
InBlock.gif
            B BTemp=new B(); 
InBlock.gif            A ATemp
=BTemp; 
InBlock.gif            ATemp.printA(); 
InBlock.gif            ATemp.valueA(); 
InBlock.gif            BTemp.printA(); 
InBlock.gif            BTemp.valueA();
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

输出:
printA
ValueB()
printB
ValueB()

直接对B的访问B BTemp = new  B(); 肯定都能理解。但是A对B的访问 A ATemp=BTemp; (与 A ATemp= new B(); 相当)为什么会得到这样的输出呢?

在讨论问题之前,先来看两个关键字virtual 和new
1、new 的意义
         new是在程序编译过程中指定方法引用新的指向地址。
2、virtual 的意义
         virtual是在程序运行时确定方法引用的地址。


问题1:类B的方法
 new public void printA()
 {
  System.Diagnostics.Debug.WriteLine("printB");
 }
不是覆盖了类A的
 public  void printA()
 {
  System.Diagnostics.Debug.WriteLine("printA");
 }
了吗?怎么还会输出printA呢?

那是因为new方法只在本类被实例化时才会覆盖父类的方法,它并不直接覆盖父类的方法。
而A ATemp= new B(); 由于类A在编译的时候已经确定了它的结构,除了标明virtual 的成员都已经被固定,而virtual 成员的引用地址是动态执行的。程序运行时,在父类访问子类的时候,需要把子类转换成父类,而子类对virtual 的覆盖将告诉父类的virtual 成员引用的实际地址。new 关键字是不起作用的。new是在编译的时候确定的新引用地址,不会对父类产生影响。

问题2:类B的 
public override void valueA()
 {
  System.Diagnostics.Debug.WriteLine("ValueB()");
 }
方法为什么覆盖了父类的
 public virtual void valueA()
 {
  System.Diagnostics.Debug.WriteLine("ValueA");
 }
方法。

答案就是上面的
程序运行时,在父类访问子类的时候,需要把子类转换成父类,而子类对virtual 的覆盖将告诉父类的virtual 成员引用的实际地址。


好了,该上班了,先讨论到这。等有时间的时候再写 《探讨C#的继承(二)》 深入得讨论一下吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值