本文是深入浅出OOP第二篇,主要说说继承的话题。

继承的介绍

在OOP中,继承有如下的定义:

  • 继承是一种OOP的机制,用于派生继承预定义的类
  • 在这个继承关系中,预定义的类是基类,新类是子类
  • 继承常常用于实现代码重用
  • 继承允许子类复用基类非private的的数据和方法

继承的实现

创建一个Console工程,命名为InheritanceAndPolymorphism。添加ClassA、ClassB类,并拷贝下面的代码:

ClassA:

   class ClassA
{ } ClassB: class ClassB
{
public int x = ;
public void Display1()
{
Console.WriteLine("ClassB Display1");
}
public void Display2()
{
Console.WriteLine("ClassB Display2");
}
}

Program.cs中,调用ClassA

class Program
{
static void Main(string[] args)
{ ClassA a = new ClassA();
a.Display1();
}
}

如果运行,肯定会报错的。

Error: 'InheritanceAndPolymorphism.ClassA' does not contain a definition for 'Display1' and no extension method 'Display1' accepting a first argument of type 'InheritanceAndPolymorphism.ClassA' could be found

因为我们在ClassA中未定义Display1的方法。 下面我们重写,使ClassA继承自ClassB。

ClassA:

  class ClassA:ClassB
{ } ClassB: class ClassB
{
public int x = ;
public void Display1()
{
Console.WriteLine("ClassB Display1");
}
public void Display2()
{
Console.WriteLine("ClassB Display2");
}
}

再次运行,结果如下:

ClassB Display1

ClassA已经可以访问其基类的Display1函数了,这个简单的实例说明了继承可复用基类的妙处,下面这张图以父子财产继承关系说明了继承的意义

再来看另外一个场景,假设ClassA也有一个Display1函数,签名和其基类一样的:

class ClassA:ClassB
{
public void Display1()
{
System.Console.WriteLine("ClassA Display1");
}
} ClassB: class ClassB
{
public int x = ;
public void Display1()
{
Console.WriteLine("ClassB Display1");
}
public void Display2()
{
Console.WriteLine("ClassB Display2");
}
}

执行后结果如下:

ClassA Display1

看起来结果是对的,ClassA默认调用了自己的Display1函数,但是Visual Studio有一个警告:

Warning: 'InheritanceAndPolymorphism.ClassA.Display1()' hides inherited member 'InheritanceAndPolymorphism.ClassB.Display1()'. Use the new keyword if hiding was intended.

C#中对方法的调用首先是查询ClassA自己中有无Display1函数,再查询其基类有无Display1函数。在基类和子类出现同样函数的情况现实项目中是存在的,可能是基类代码过于陈旧了,子类既想用同签名的函数,又无法停止基类的同签名函数,故会出现这样的警告---尽管逻辑正确,但是这种设计还是有一些瑕疵的。

我们再试试在CalssA中通过base调用基类同名方法的情况:

ClassA:

  class ClassA:ClassB
{
public void Display1()
{
Console.WriteLine("ClassA Display1");
base.Display1();
}
} ClassB: class ClassB
{
public int x = ;
public void Display1()
{
Console.WriteLine("ClassB Display1");
}
public void Display2()
{
Console.WriteLine("ClassB Display2");
}
}

执行结果如下:

ClassA Display1

ClassB Display1

这个实验说明C#提供了base关键词,用于在继承中子类调用基类的函数或者变量(非private类型)。

同样的,在ClassA.Display1中调用其基类的Display2也是可以的,代码如下所示:

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
{
public int x = ;
public void Display1()
{
Console.WriteLine("ClassB Display1");
}
public void Display2()
{
Console.WriteLine("ClassB Display2");
}
} /// <summary>
/// ClassA: acting as derived class
/// </summary>
class ClassA : ClassB
{
public void Display1()
{
Console.WriteLine("ClassA Display1");
base.Display2();
}
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
class Program
{
static void Main(string[] args)
{
ClassA a = new ClassA();
a.Display1();
Console.ReadKey();
}
}

执行结果如下:

ClassA Display1

ClassB Display2

那么可否通过基类调用其子类的函数呢?

/// <summary>
/// ClassB: acting as base class
/// </summary>
class ClassB
{
public int x = ;
public void Display1()
{
Console.WriteLine("ClassB Display1");
}
} /// <summary>
/// ClassA: acting as derived class
/// </summary>
class ClassA : ClassB
{
public void Display2()
{
Console.WriteLine("ClassA Display2");
}
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
class Program
{
static void Main(string[] args)
{
ClassB b = new ClassB();
b.Display2();
Console.ReadKey();
}
}

运行报错:

Error: 'InheritanceAndPolymorphism.ClassB' does not contain a definition for 'Display2' and no extension method 'Display2' accepting a first argument of type 'InheritanceAndPolymorphism.ClassB' could be found

原因是继承无法实现逆向调用,既基类无法调用子类。

除了构造函数和析构函数,子类继承了其基类的一些(包括private的成员变量和成员函数,只是无法访问)。

在C#中,一个类默认继承的是object类型,object是C#所有引用类型的基类;同时,继承具有传递性,如ClassC继承自ClassB,ClassB继承自ClassA,则ClassC可完全复用ClassA的数据和函数---ClassC继承了ClassA。

C#中所有的类型都可被继承吗?

public class ClassW : System.ValueType
{
} public class ClassX : System.Enum
{
} public class ClassY : System.Delegate
{
} public class ClassZ : System.Array
{
}

执行结果:

'InheritanceAndPolymorphism.ClassW' cannot derive from special class 'System.ValueType'

'InheritanceAndPolymorphism.ClassX' cannot derive from special class 'System.Enum'

'InheritanceAndPolymorphism.ClassY' cannot derive from special class 'System.Delegate'

'InheritanceAndPolymorphism.ClassZ' cannot derive from special class 'System.Array'

运行的结果让人抓狂

在C#中,自定义类无法继承自C#内置的一些类,如System.ValueType, System.Enum, System.Delegate, System.Array, etc。

下面这个例子我们再看看C++中的多类继承是否可在C#中实现:

    public class ClassW
{
} public class ClassX
{
} public class ClassY : ClassW, ClassX
{
}

执行结果:

Compile time Error: Class 'InheritanceAndPolymorphism.ClassY' cannot have multiple base classes: 'InheritanceAndPolymorphism.ClassW' and 'ClassX'.

执行结论是:C#仅支持单类继承,不支持C++的这种星型继承关系。 要使用星型继承关系,请用接口实现。

那么可否实现循环依赖继承呢?

   public class ClassW: ClassY
{
} public class ClassX: ClassW
{
} public class ClassY : ClassX
{
}

代码逻辑很简单,ClassW继承自ClassY,ClassX继承自ClassW, ClassY继承自ClassX。

但是编译后报错了:

Error: Circular base class dependency involving 'InheritanceAndPolymorphism.ClassX' and 'InheritanceAndPolymorphism.ClassW'.

我们得出一个结论,C#中不许环形依赖继承。

实例对象的是否可赋值

ClassB:
public class ClassB
{
public int b = ;
} ClassA: public class ClassA
{
public int a = ;
}

Program.cs 代码如下

/// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
ClassA classA = new ClassA();
classA = classB;
classB = classA;
}
}

我们尝试判断ClassA、ClassB的对象是否可赋值。

编译的结果是:报错了

Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA' Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'

尽管ClassA和ClassB里面的数据成员变量a数据一致,都为100,但是这里用等号比较的是类型--引用地址,故无法进行赋值。

我们再来试试继承关系的:

public class ClassB
{
public int b = ;
} public class ClassA:ClassB
{
public int a = ;
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
ClassA classA = new ClassA();
classA = classB;
classB = classA;
}
}

ClassA继承自ClassB,我们希望可以直接赋值其实例对象。

运行结果如下:

Error: Cannot implicitly convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'.

运行结论:C#中子类对象可直接赋值给基类对象,基类对象需要往下强转。代码修改如下:

public class ClassB
{
public int b = ;
} public class ClassA:ClassB
{
public int a = ;
} /// <summary>
/// Program: used to execute the method.
/// Contains Main method.
/// </summary>
public class Program
{
private static void Main(string[] args)
{
ClassB classB = new ClassB();
ClassA classA = new ClassA();
classB=classA;
classA = (ClassA)classB;
}
}

这样编译就通过了。

如果ClassA不继承自ClassB,则这种强转在C#中是会报错的:

Cannot convert type 'InheritanceAndPolymorphism.ClassA' to 'InheritanceAndPolymorphism.ClassB'

Cannot convert type 'InheritanceAndPolymorphism.ClassB' to 'InheritanceAndPolymorphism.ClassA'

本节结论

  • 无法阻止子类覆盖基类同签名方法
  • 继承关系是子类的同签名方法先查找,再查找其基类的
  • base关键字被C#用于在子类中调用基类函数、变量
  • 继承关系不可逆转
  • 除了构造函数、析构函数,子类继承了基类的一些
  • 自定义类默认继承自Object类型,但是C#的这些类型不能被继承:System.ValueType, System.Enum, System.Delegate, System.Array, etc.
  • C#不支持从多类继承
  • C#不支持循环继承
  • 子类对象可直接赋值给基类,反之需要强转

原文地址:Diving in OOP (Day 2): Polymorphism and Inheritance (Inheritance)

深入浅出OOP(二): 多态和继承(继承)的更多相关文章

  1. 深入理解OOP(二):多态和继承(继承)

    本文是深入浅出OOP第二篇,主要说说继承的话题. 深入理解OOP(一):多态和继承(初期绑定和编译时多态) 深入理解OOP(二):多态和继承(继承) 深入理解OOP(三):多态和继承(动态绑定和运行时 ...

  2. PHP基础OOP(二) 多态

    PHP 基础  多态  ====================多态是一种思想:从一个基类中派生,响应一个虚命令,产生不同的结果.                不同的对象执行相同的方法而产生不同的行 ...

  3. 深入理解OOP(三):多态和继承(动态绑定和运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...

  4. 深入浅出OOP(三): 多态和继承(动态绑定/运行时多态)

    在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 运行时多态或迟绑定.动态绑定 在C#语音中,运行时 ...

  5. JS中OOP之模拟封装和继承和this指向详解

    大家好,今天我带大家学习一下js的OOP, 大家都知道,面向对象有三个基本特征,继承,封装和多态,面向对象的语言有那么几种,C++,PHP,JAVA等,而功能强大的JS可以模拟实现面向对象的两大特征, ...

  6. js oop中的三种继承方法

    JS OOP 中的三种继承方法: 很多读者关于js opp的继承比较模糊,本文总结了oop中的三种继承方法,以助于读者进行区分. <继承使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方 ...

  7. c/c++ 继承与多态 容器与继承3

    c/c++ 继承与多态 容器与继承2 巩固了容器里放智能指针的用法,但是有个问题,对于使用Basket类的用户来说,必须添加的是智能指针,如果能直接添加一个普通的类的对象的话,用起来就方便的多了,所以 ...

  8. c/c++ 继承与多态 容器与继承2

    c/c++ 继承与多态 容器与继承1说明了容器里使用继承关系的方法,这里再弄一个练习,巩固一下. 做一个类Basket,它有个multiset成员,key是智能指针std::shared_ptr< ...

  9. 二十二. Python基础(22)--继承

    二十二. Python基础(22)--继承 ● 知识框架   ● 继承关系中self的指向 当一个对象调用一个方法时,这个方法的self形参会指向这个对象 class A:     def get(s ...

随机推荐

  1. C#页面前台绑定数据 <%%><%#%><%=%>

    ASP.net前台绑定用的最多,今天小小总结一下. 1:<%#Eval("")%> 2:<%#Bind("")%> 3:<%=变量 ...

  2. Collection List Set和Map用法与区别

    labels:Collection List Set和Map用法与区别 java 散列表 集合 Collection           接 口的接口      对 象的集合   ├   List   ...

  3. C# 使用js正则表达式,让文本框只能输入数字和字母,最大长度5位

    使用js正则表达式,让文本框只能输入数字和字母,最大长度5位,只需要加个onkeyup事件,即可简单实现 <asp:TextBox ID="txtBegin" runat=& ...

  4. TransactionScope 事务使用说明

    TransactionScope是.Net Framework 2.0滞后,新增了一个名称空间.它的用途是为数据库访问提供了一个“轻量级”[区别于:SqlTransaction]的事物.使用之前必须添 ...

  5. POJ Ant Counting DP

    dp[i][j]表示前i种蚂蚁组成元素个数为j的集合有多少种. 则dp[i][j] = dp[i-1][j] + dp[i-1][j-1] + ... + dp[i-1][ max(0,j-a[i]) ...

  6. NFS配置

    一,配置nfs服务端 nfs服务端IP:192.168.1.10 1,安装nfs [root@localhost ~]# yum install -y nfs-utils Loaded plugins ...

  7. ios调用第三方程序打开文件,以及第三方调用自己的APP打开文件

    1.自己的APP调用第三方打开文件 主要是使用  UIDocumentInteractionController  类   并实现 UIDocumentInteractionControllerDel ...

  8. zabbix告警“Zabbix poller processes more than 75% busy”

    告警原因: 1.某个进程卡住了, 2.僵尸进程出错,太多,导致慢了 3.网络延迟(可忽略) 4.zabbix消耗的内存多了 告警危害: 普通告警,暂无危害(但是最好处理) 处理方法: 一:简单,粗暴( ...

  9. “ExternalException (0x80004005): GDI+ 中发生一般性错误”的问题 .

     原因一般是写入文件时,.net没有该目录的写入权限. 解决方案:增加iis(对aspx而言)对该目录的写入权限.

  10. Javascript 添加自定义静态方法属性JS清除左右空格

    例如加trim()清除左右空格 String.prototype.trim=function() { return this.replace(/(^\s*)|(\s*$)/g,''); } 调用 va ...