深入理解OOP(二):多态和继承(继承)
本文是深入浅出OOP第二篇,主要说说继承的话题。
深入理解OOP(四):多态和继承(C#中的抽象类)
深入理解OOP(五):C#中的访问修饰符(Public/Private/Protected/Internal/Sealed/Constants/Static and Readonly Fields)
深入理解OOP(六):枚举(实用方法)
深入理解OOP(七):属性(实用方法)
深入理解OOP(八):索引器(实用方法)
深入理解OOP(九):事件(深入理解)
继承的实现
创建一个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 thenew
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 代码如下
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#不支持循环继承
- 子类对象可直接赋值给基类,反之需要强转
译文地址:http://www.cnblogs.com/powertoolsteam/p/Diving-in-OOP-Polymorphism-and-Inheritance-Part.html
原文地址:Diving in OOP (Day 2): Polymorphism and Inheritance (Inheritance)
深入理解OOP(二):多态和继承(继承)的更多相关文章
- 深入理解OOP(三):多态和继承(动态绑定和运行时多态)
在前面的文章中,我们介绍了编译期多态.params关键字.实例化.base关键字等.本节我们来关注另外一种多态:运行时多态, 运行时多态也叫迟绑定. 深入理解OOP(一):多态和继承(初期绑定和编译时 ...
- PHP基础OOP(二) 多态
PHP 基础 多态 ====================多态是一种思想:从一个基类中派生,响应一个虚命令,产生不同的结果. 不同的对象执行相同的方法而产生不同的行 ...
- 深入理解OOP(四): 多态和继承(抽象类)
在本文中,我们讨论OOP中的热点之一:抽象类.抽象类在各个编程语言中概念是一致的,但是C#稍微有些不一样.本文中我们会通过代码来实现抽象类,并一一进行解析. 深入理解OOP(一):多态和继承(初期绑定 ...
- 深入理解OOP(第一天):多态和继承(初期绑定和编译时多态)
在本系列中,我们以CodeProject上比较火的OOP系列博客为主,进行OOP深入浅出展现. 无论作为软件设计的高手.或者菜鸟,对于架构设计而言,均需要多次重构.取舍,以有利于整个软件项目的健康构建 ...
- 【转】java提高篇(二)-----理解java的三大特性之继承
[转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...
- 深入理解Java面向对象三大特性 封装 继承 多态
1.封装 封装的定义: 首先是抽象,把事物抽象成一个类,其次才是封装,将事物拥有的属性和动作隐藏起来,只保留特定的方法与外界联系 为什么需要封装: 封装符合面向对象设计原则的第一条:单一性原则,一个类 ...
- JS中OOP之模拟封装和继承和this指向详解
大家好,今天我带大家学习一下js的OOP, 大家都知道,面向对象有三个基本特征,继承,封装和多态,面向对象的语言有那么几种,C++,PHP,JAVA等,而功能强大的JS可以模拟实现面向对象的两大特征, ...
- js oop中的三种继承方法
JS OOP 中的三种继承方法: 很多读者关于js opp的继承比较模糊,本文总结了oop中的三种继承方法,以助于读者进行区分. <继承使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方 ...
- c/c++ 继承与多态 容器与继承3
c/c++ 继承与多态 容器与继承2 巩固了容器里放智能指针的用法,但是有个问题,对于使用Basket类的用户来说,必须添加的是智能指针,如果能直接添加一个普通的类的对象的话,用起来就方便的多了,所以 ...
随机推荐
- javascript-建造者模式
建造者模式笔记 1.工厂模式主要是为了创建对象实例或者类簇(抽象工厂),关心的是最终产出(创建)的是什么,不关心你创建的整个过程,仅仅需要知道你最终创建的结果 2.建造者模式目的也是为了创建对象,但是 ...
- 在Linux下使用gradle自动打包
一.下载软件包 1.下载地址 wget https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz wget http://services ...
- cocos2d之列表容器节点再排序
第一处:获取使用类中传出的数据对象 第二处:清除列表容器中的数据且保存数据缓存 第三处:使用刚创建的函数再排序
- Linux IPC POSIX 信号量
模型 #include<semaphore.h> #include<sys/stat.h> #include<fcntl.h> sem_open() //初始化并打 ...
- 异常处理try-catch-finally
php5.5新增 Finally模块 try { //好好干,出了问题不要怕,外面有人接应} catch (HttpException $e) { //时刻准备着,处理上面抛出的HTTP问 ...
- ELF Format 笔记(一)—— 概述
ilocker:关注 Android 安全(新手) QQ: 2597294287 ELF Object files 参与程序的链接和执行,从这两个角度分别有两种视图: ELF header 位于文件的 ...
- vim linux SecureCRT vim颜色的设置
解决方法: 1.首先按照环境一的方法检查一下,如果环境一的情况不在进行第二步. 2.修改终端TERM这个环境变量: 1)export命令 临时生效 # echo $TERM xterm #如果结果 ...
- POJ1523 SPF[无向图割点]
SPF Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8139 Accepted: 3723 Description C ...
- USACO1.2Milking Cows
题目描述 三个农民每天清晨5点起床,然后去牛棚给3头牛挤奶.第一个农民在300秒(从5点开始计时)给他的牛挤奶,一直到1000秒.第二个农民在700秒开始,在 1200秒结束.第三个农民在1500秒开 ...
- JavaScript RegExp 对象
JavaScript RegExp 对象 RegExp 对象用于规定在文本中检索的内容. 什么是 RegExp? RegExp 是正则表达式的缩写. 当您检索某个文本时,可以使用一种模式来描述要检索的 ...