【C#】OOP之继承那点事
前言:
继承这点事,说多不多,说少不少,这里只描述了一些我认为的基础篇,望各位大神指教。
本节参照了C#高级编程和Think in java对继承的描述,我个人认为OOP只是思想,故看明白一个就说通的,只是语法上的区别。
- 权限限制关键字
- 类继承
- 类继承基本写法
- 类继承的好处
- 继承中的Virtual(虚方法)
- 抽象类
- 类继承的坏处
- 执行循序
- 不可继承的类
- 接口继承
1.类继承
类继承基本写法:
public class SuperClass : Object{} public class SubClass : SuperClass{}
我们用":"来表示类的继承, 而且每个类只能有一个父类(这个靠谱啊,你不可能有两个亲身父亲,C++不论)。
SuperClass继承了Object类, Object类是顶级类,你自定义的顶级类(这里说SuperClass)会自动继承这个类(我看有很多人说:你的每个类都会继承Object,我们说过,你只能有一个亲生父亲,这样的说法不是很严谨,这样的Tier1, Tier2, Tier3的层次下来,你的高层可以直接用Object所开放的一些方法)。
类继承的好处:
我们先来看些该死的温柔(类)!!!
public class Dog
{
public string Name { get; set; }
public string Age { get; set; } public void Run()
{
Console.WriteLine("Dog is running.");
}
} public class Cat
{
public string Name { get; set; }
public string Age { get; set; } public void Run()
{
Console.WriteLine("Cat is running.");
}
}
粗看一下,没什么问题,猫类和狗类 都有名字,年龄和一个跑的方法。 (当年,我写完还点头,双手叉腰,嗯,很好,不错--傻的一塌糊涂,冏)
但是如果那天有个变态叫你把所有动物都写一边,你开始造轮子了,1234567.....,终于要完工了, 大喜过望,那个变态回来告诉你,不好意思,弄错了,年龄没有意义,可以去掉(纳尼....). 这个时候你就需要再去1234567....,oh Fuck...难道我不能只改一次吗?
完 全 可 以->继承
public abstract class Animal
{
public string Name { get; set; }
public string Age { get; set; } public void Run()
{
Console.WriteLine(string.Format("{0} is running.", Name));
}
}
public class Dog : Animal
{ } public class Cat : Animal
{ }
代码所示之处我们提取一个父类:Aniaml(抽象类..过后再说这个).我们重新来完成那个变态的需求,我们只要开辟一个类然后继承一下Animal就好了,
(场景恢复)嘿,年龄没有意义,可以去掉(简单....),我们只要把Animal中的年龄去掉,就OK了,一步到位。
到这里看出来继承的好处没:消除你重复的代码,让修改更加的方便。
继承中的Virtual(虚方法)
这里又有人提出另一个问题了,如果我发现我父类的方法不能满足我的条件了,但是我又不想重载,我能重写吗?答案:完全可以。
C#提供一个Virtual的一个标识,可以用于方法重写(java都说虚方法)
public abstract class Animal
{
public string Name { get; set; }
public string Age { get; set; } public virtual void Run()
{
Console.WriteLine(string.Format("{0} is running.", Name));
}
}
public class Dog : Animal
{
public override void Run()
{
Console.WriteLine("Dog is running.");
}
} public class Cat : Animal
{ }
看Animal中的Run方法加上了virtual标识这个方法说虚方法,也就说可以被重写,在Dog类中,我们使用了override标识我们重写了Run的方法,这样我们在实例化对象Cat的时候,我调用Run方法就是我们重写过的。
有人提出疑问了:如果不写virtual 和 override,直接在Cat中重写Run方法,实例化Cat cat=new Cat()后调用Run方法也是一样的结果。 回答:C#不像JAVA都说虚方法,如果不想写virtual 和 override的话,CLR认为这个是隐藏,所以要在子类的Run方法上添加一个new关键字,如果不添加会出现
warning。
public class Cat:Animal
{
public new void Run()
{
Console.WriteLine("....");
}
}
New 关键字代表我要隐藏父类同名,同参数的方法(这里有几个可以讨论的地方,在多态那章会提出来说)
抽象方法
为什么会出现抽象方法,OOP告诉我们,实例化就像我们现实中创造一件东西,就如上例来看,我们如何去创造一个叫Animal的一个实体,这样是不是很奇怪,所以我们出现了抽象类。 抽象类无法被实例化,只能被继承使用。public abstract class Animal,在class前面定义abstract关键字就好了。
抽象类可以定义抽象的方法,用abstract关键字来标识,所有继承该抽象类的子类必须实现这个抽象方法,来一个实例:
public abstract class Animal
{
public string Name { get; set; }
public string Age { get; set; } public virtual void Run()
{
Console.WriteLine(string.Format("{0} is running.", Name));
} public abstract void Scream();
}
public class Dog : Animal
{
public override void Run()
{
Console.WriteLine("Dog is running.");
} public override void Scream()
{
throw new NotImplementedException();
}
} public class Cat : Animal
{ public override void Scream()
{
throw new NotImplementedException();
}
}
在Animal的抽象类中(我们说了为什么把Animal定义成抽象类),定义了一个Scream()的抽象方法,我们看见了。抽象方法是没有实现体的,直接后面跟上";"作为结束。在子类Dog和Cat类里,我们实现了Scream这个方法(不可以不实现,只要你用IDE工具,编译时会报错),我们在来看子类的Scream方法有override的关键字,所以abstract被认为是虚方法,用法类似。
注:这里还没有说接口,抽象类和接口一起用非常的常见,等说到接口,再详细的来说下抽象类的其他作用。
类继承的坏处
所谓有得必有失,继承给我们带来了很多好的地方,消除代码重复,让层次更加清晰,修改方便等好处,但是随之带来的坏处也是很明显的,当我们继承的层次变多了,整个的架构会变得十分臃肿而导致不清晰,拿个简单的例子来说,假设我们说从猩猩进化而来,那尾巴是否已经没有了,而猩猩还是有的,这就会导致使用的迷糊,我们做类的时候要把该类的东西放在此类中,做父类的时候把对应的公共的东西提出来,而一直用继承的话很恐怖,所以这里又引出一个新的概念->组合。
组合概念就说在类中放一个其他类的对象,如果要用就赋值,不要用了就直接拿掉(父亲我们总不能放弃吧)。
执行循序
public abstract class SuperClass
{
public static string StaticField = "StaticFieldInSuperClass"; private string _privateField = "_privateFieldInSuperClass";
public string publicField = "publicFieldInSuperClass"; public SuperClass()
{ } }
public class SubClass : SuperClass
{
public static string StaticFieldInDog = "StaticFieldInSubClass"; private string _privateField = "_privateFieldInSubClass";
public SubClass()
{ }
}
我们看一下这两个类SuperClass里面有静态字段,私有字段,共有字段和一个构造,SubClass有一个静态字段,私有字段。
我们实例化SubClass subClass=new SubClass()的时候,执行循序如下:
1.先初始化子类(subclass)的字段。
2.执行子类构造,这时会发现它拥有父类,所以暂停初始化子类构造,而初始化父类(SuperClass)
3.初始化父类(SuperClass)的字段
4.执行父类构造
5.返回子类继续初始化子类构造
这里有兴趣的朋友可以直接debug看步骤就明白了。
不可继承的类
拥有关键字sealed类都不能被继承。
public sealed class ConfigHelper
{ }
故可以认为里面所有的字段和方法都说自带sealed,因为无法继承就无法重写。
2.接口继承
关于前言Class的抽象类,我们说到抽象类可以实现抽象方法,在Animal中有一个Run的抽象方法,但是我们人也能Run, 而不能去继承Animal,因为我们的关系图应该在People或者Human下比较靠谱。 我们这时就可以用接口来做了。
我的概念中的接口:
1.是一个规则,制定程序员只能做什么的规则
2.只关注行为,不关注字段的一个神奇的产物
3.用来做底层抽象和设计框架的不二神器
public interface IRun
{
void Run();
} public abstract class Animal : IRun
{
public abstract void Run();
}
public class Dog : Animal
{
public override void Run()
{
throw new NotImplementedException();
}
}
public abstract class People : IRun
{
public abstract void Run();
}
public class Man : People
{
public override void Run()
{
throw new NotImplementedException();
}
}
我们来看一下上面的代码,People和Animal都说抽抽象类,我们并没有实现IRun接口下的Run方法,而是直接做成了抽象方法(这里可以证明,接口里面的方法都说抽象方法),而是由我们的子类Man和Dog分别去实现了,这样可以说明,接口关注的只是行为,因为IRun接口可以被所有可以跑的物体去实现。
关于第一个点:我强烈建议不要在类中任意的去加public方法,因为我建议只要有接口,就用接口作为对象,这样的好处有几点:
1.所有实现了该特定接口的类看起来都这样
2.接口被用来建立类与类之间的协议。(同步开发的时候,只关注接口就行了)
3.定义了规则,无论你底层的编写人员怎么加public方法你是看不见的,因为作为高层我只认接口里面的方法(这里要明白多态)。
4.接口可以跨类继承体系来使用(就像IRun run=new Dog(), IRun run=new Man() 这样)
对于这篇来说是我对接口浅显的理解,肯定不全,我其实觉得接口在框架级上的可以说的很多,但说这个技术,我真心觉得没什么好说的。下面是我对接口一些功能的总结:
1.接口 能多继承接口,类可以多继承实现。
2.接口里能包含:事件、属性、索引器、静态方法、静态字段、静态构造函数以及常量。
3.出来抽象类以外,所有实现接口的类都要实现其定义的方法
【C#】OOP之继承那点事的更多相关文章
- 【C#】OOP之多态那点事
前言: 对菜鸟开发者的忠告:花一万个小时练习 Coding,不要浪费一万小时无谓地 Debugging(也就说看代码) 看上面的UML图,我们创建一个抽象的Instrument类,类中有一个抽象方法p ...
- 探讨 JS 的面向对象中继承的那些事
最近学了 JS 的面向对象,这篇文章主要是探讨 JS 的面向对象中继承的那些事. JS中继承的特点: 1.子类继承父类: 2.子类可以用父类的方法和属性 3.子类的改变可以不影响父类 下面用一个例子来 ...
- OOP三类继承的区别
OOP继承的区别提纲: 1. 普通类继承,并非一定要重写父类方法.2. 抽象类继承,如果子类也是一个抽象类,并不要求一定重写父类方法.如果子类不是抽象类,则要求子类一定要实现父类中的抽象方法.3. 接 ...
- JavaScript中继承的那些事
引言 JS是一门面向对象的语言,但是在JS中没有引入类的概念,之前特别疑惑在JS中继承的机制到底是怎样的,一直学了JS的继承这块后才恍然大悟,遂记之. 假如现在有一个“人类”的构造函数: functi ...
- Golang OOP、继承、组合、接口
http://www.cnblogs.com/jasonxuli/p/6836399.html 传统 OOP 概念 OOP(面向对象编程)是对真实世界的一种抽象思维方式,可以在更高的层次上对所 ...
- 关于JavaScript继承的那些事
在JavaScript中,对象的创建可以脱离类型(class free),通过字面量的方式可以很方便的创建出自定义对象. 另外,JavaScript中拥有原型这个强大的概念,当对象进行属性查找的时候, ...
- php面向对象的特性:OOP的继承
1.关键字extends 2.PHP只支持单继承,不支持方法重载 /*使用protect 调用字段*/ class Computer{ //父类的字段 protected $_name="联 ...
- 说一说js中__proto__和prototype以及原型继承的那些事
在面试中遇到过,问js如何实现继承,其实最好的方式就是构造函数+原型,今天在讨论中,发现自己以前理解上的一些误区,特地写出来,最近都比较忙,等手上的项目做完,可以来做个总结. 先说我以前没有认识到位的 ...
- JS 8-5 OOP 实现继承的方式
function Person(){} function Student(){} Student.prototype = Person.prototype;//此继承方式是错误的,当我们改变Stude ...
随机推荐
- Javascript - 栈 和 单链表
最近在重温数据结构,于是写了一些代码玩玩,都是很初级的,表喷各位.... function Stack() { this.dataStore = []; this.top = 0; } Stack.p ...
- 用户管理 之 Linux 用户(user)和用户组(group)管理概述
一.理解Linux的单用户多任务,多用户多任务概念:Linux 是一个多用户.多任务的操作系统:我们应该了解单用户多任务和多用户多任务的概念: 1.Linux 的单用户多任务:单用户多任务:比如我们以 ...
- Cheat (tldr, bropages) - Unix命令用法备忘单
cheat 是一个Unix命令行小工具,用来查询一些常用命令的惯用法(我们都知道,man page阅读起来太累了,常常是跳到最后去看 examples,但并不是所有man pages里面都有examp ...
- CSS3绘制旋转的太极图案(一)
实现步骤: 基础HTML: <div class="box-taiji"> <div class="circle-01">< ...
- 转:php park、unpark、ord 函数使用方法(二进制流接口应用实例)
在工作中,我也逐渐了解到park,unpark,ord对于二进制字节处理的强大. 下面我逐一介绍它们. park,unpark,ord这3个函数,在我们工作中,用到它们的估计不多. 我在最近一 ...
- dell 电脑关闭触摸板的。
桌面计算机(点击右键)----管理----设备管理器-----鼠标------选择触摸板(ps/2 兼容鼠标)---右击------跟新驱动-------浏览计算机查找------从计算机列表中选择- ...
- Windows 7远程桌面连接Ubuntu 16.04
转自:http://jingyan.baidu.com/article/8ebacdf0cdc64949f75cd555.html 从Windows 7远程到Windows系统比较简单,只要对方电脑开 ...
- 【原创】MYSQL++源码剖析——前言与目录
终于完成了! 从第一次想写到现在真的写好大概花了我3个月时间.原来一直读人家的系列文章,总感慨作者的用心良苦和无私奉献,自己在心里总是会觉得有那么些冲动也来写一个. 最开始的麻烦是犹豫该选哪个主题.其 ...
- SmartJS 第一期(0.1)发布 - AOP三剑客
隔了好久才终于又发布了一点东西,SmartJS是最近才开始搞的一个开源js库,目的是做一些比较有特点的事情(smartjs暂时也是依赖于jquery). SmartJS的内容规划比较多,也无法在短时间 ...
- 疯狂的ASP.NET系列-第一篇:啥是ASP.NET
最近想学下ASP.NET,于是在网店上看到一本书叫做ASP.NET高级程序设计,老婆在旁边问了句:“这个不是DSP(数字信号处理,大学读的电子,所以这个比较熟),是ASP啊,什么是ASP啊?”.我想了 ...