C#OOP之八 继承 接口和抽象类

继承

在现实生活中有所谓的“种瓜得瓜、种豆得豆”的说法,在生物学概念上就是“遗传”的概念,在面向对象中“继承”就类似于生物学中的遗传,通过继承,可以更好的实现代码的重用(复用,多次使用的意思)、增加扩展性、简化代码等。

下面是现实生活中的引用:

定义与使用继承

继承一次最常用的就是通过合法程序(比如遗嘱)从别人那里接受财产或爵位等,有点类似于世袭制。

另外一个含义,是人从父母那里继承一些特征,如果孩子从父母继承的身高、相貌等特征。那么在什么情况下使用继承,以及在程序中应该如何定义呢?

首先,继承一般使用在类之间有一定的层次关系,即一个类已经包含了其他类的一些属性与方法,比如,雇员类包含了技术员工、客服员工、软件支持、经理等的属性和方法,这时,我们把雇员类成为父类,技术员工等类成为子类,子类可以通过继承机制来使用父类的属性和方法。

概括来说:继承需要is a的关系(技术员工 is a 雇员)

在C#中,使用“:”来表示一个类继承自另外一个类。格式如下:

class   技术员工:雇员

{

//技术员工的属性定义

// 技术员工的方法定义

}

现在需要你为一家卡通影视公司开发商业软件,其中涉及一个会说话的鸭子(比如唐老鸭),在此之前已经有了,普通鸭子类了。代码如下:

Class Duck

{

private    string name;

public string Name

{

get{return name;}

set{name=value;}

}

public void Quck()

{

Console.WriteLine(“嘎嘎嘎”);

}

public void Swimming()

{

Console.WriteLine(“游啊游”);

}

}

那么,现在唐老鸭会说人话,怎么办呢?同时还会“嘎嘎嘎”叫,原来的方式是在Duck类里增加方法

public void Speak()

{

Console.WriteLine(“说人话了^.^”);

}

然后在Main()方法中调用,使用继承后的方法:

class TangDuck:Duck

{

public void Speak()

{

Console.WriteLine(“说人话了^.^”);

}

}

同理可以在Main()中进行类的声明与调用

static void Main(string[]args)

{

TangDuck tanglaoya=newTangDuck();

tanglaoya.Speak();              //可以实现说话功能

}

我们看到类TangDuck在使用继承实现Speak时,在类名后跟了个“:”,冒号在此处的含义为“继承自”的意思。继承特点如下:

1.有助于代码的重用;

2.代码维护和书写都简单得多;

3.父类的可继承数据成员和方法可用于子类;

4.子类可以轻易的获得数据成员和方法;

编码实践:试完成作业1

深入理解继承

1.访问修饰符在继承中的使用范围

3.继承的单根性

4.继承自上而下是一种逐层具体化的过程,而自下向上是一种逐层抽象化得过程,这种抽象化关系反应为上下层之间的继承关系。例如:最高层的动物具有最普遍的特征,而最底层的人则具有较具体的特征。

项目1:使用访问修饰符深入学习继承

项目背景:实现雇员类对人类的代码重用。

解决方案:学习如何利用继承机制来实现代码重用。

任务1:编写代码

using System;

usingSystem.Collections.Generic;

usingSystem.Text;

namespaceExtends

{

class Person

{

//字段

private stringname;

private stringaddress;

private stringage;

private stringemail;

//属性

public stringName

{

get{ return name; }

set{ name =
value; }

}

protected stringAddress

{

get{ return address; }

set{ address =
value; }

}

public stringAge

{

get{ return age; }

set{ age =
value; }

}

internal stringEmail

{

get{ return email; }

set{ email =
value; }

}

//方法

public voidShowName()

{

Console.WriteLine("姓名:" + name);

}

protected voidShowAddress()

{

Console.WriteLine("地址:" + address);

}

private voidShowAge()

{

Console.WriteLine("年龄:" + age);

}

internal voidShowEmail()

{

Console.WriteLine("邮件:" + email);

}

//构造函数

public Person()

{

name = "活人";

address = "人世间 ";

age = "1";

email = "[email protected]";

}

}

class Employee:Person    //Employee类继承自Person类

{

//字段:部门

private floatdepartment;

//Employee类的方法

public voidShow()

{

Console.WriteLine(Name+ Address + Email);

}

}

class Program

{

static voidMain(string[]args)

{

EmployeetangJun =
new Employee();

tangJun.ShowName();

tangJun.Name = "唐峻 ";

tangJun.ShowEmail();

tangJun.Show();

}

}

}

任务2:编译程序:

任务3:运行效果

姓名:活人

邮件:[email protected]

唐峻 人世间 [email protected]

base和this关键字

通过前面的学习,我们知道子类只能继承父类非private的属性和方法,系统在创建对象时必须调用类的构造方法,那么在创建子类对象时父类的构造方法是怎样被调用的呢?示例如下:

using System;

namespace ExtendsExam

{

classMyBase

{

publicMyBase()

{

Console.WriteLine(“基类对象被创建”);

}

~MyBase()

{

Console.WriteLine(“基类对象被销毁”);

}

}

class SubClass :MyBase()

{

public SubClass()

{

Console.WriteLine(“子类对象被创建”);

}

~SubClass()

{

Console.WriteLine(“子类对象被销毁”);

}

}

classProgram

{

static void Main(string[]args)

{

SubClass sc=new SubClass();

}

}

}

运行效果:

基类对象被创建

子类对象被创建

子类对象被销毁

基类对象被销毁

通过上述的案例,我们会发现子类自动调用了父类的构造函数和析构函数。如果父类有多个构造函数(即父类构造函数重载的情况),子类如何知道调用父类的那个构造函数呢?此时,用base关键字指定调用父类的具体构造函数就比较有用。

base的使用:

n       调用父类的属性和方法

public voidDoWork()

{

string message = string.Format(

" {0}上班了,时间{1}",

base.Name, base.Time);

}

n       调用父类的构造函数

publicManager(string name, Genders gender,

int age,string position,int allowance)

:base(name,gender,age)

{

//经理类扩展的属性

this.position = position;

this.allowance = allowance;

}

案例:

usingSystem;

usingSystem.Collections.Generic;

usingSystem.Text;

namespace Test

{

class Person

{

protected stringname;

public stringName

{

get{ return name; }

}

public Person(string_name)

{

name = _name;

}

public voidShowName()

{

Console.WriteLine("name={0}", name);

}

}

//Person类的子类

class Employee:Person

{

public stringid;

public Employee(stringsname,string sid):base(sname)

{

id = sid;

}

public voidShow()

{

base.ShowName();       
//利用base调用方法

Console.WriteLine("name={0}",base.name);  
//利用base调用父类字段

Console.WriteLine("id={0}", id);

}

}

class Program

{

static voidMain(string[]args)

{

Employeeemp =
new Employee("聂亚龙","MS007");

emp.Show();

}

}

}

this关键字:用来调用本类成员

通常也可以隐藏this,MSDN总结如下:

·                限定被相似的名称隐藏的成员,例如:


public Employee(string name, string alias)

{

this.name = name;

this.alias = alias;

}

·                将对象作为参数传递到其他方法,例如:


CalcTax(this);

this指代对象本身,用于访问本类的常量、字段、属性和方法,而且不管访问元素师任何访问级别。另外,静态成员不是对象的一部分,因此不能在静态方法中引用this。

抽象类定义及其使用

在理解抽象类和抽象方法之前,我们先来看一下“抽象”是什么意思,汉语词典“抽象”含义如下:

1.      将复杂物体的一个或几个特性抽出去,而只去注意其他特性的行动或过程(主要看是否与系统研究的目标一致)

2.   将几个有区别的物体的共同性质或特性形象地抽取出来或孤立地进行考虑的行动或过程。

3.   抽象对于将东西分类是必需的。

4.   摘要、提炼,抽象化。

从词典解释,我们会发现程序里的抽象理论实际上是在仿效现实中的抽象理论和方法。

抽象类:好比一篇摘要,摘要中涉及的很多要点都要在文章的各个部分实现,同样抽象类功能需要子类来实现。

我们在查找某篇文章时往往先看摘要,摘要可以代表这篇文章,也同样通过查看抽象类你可以明晰子类提供的功能,并且抽象类对象也可以代表子类实例行使功能。

抽象类最重要的三个描述

n      抽象类是子类的一个描述

n      抽象类不能自己实例化,但可以代表子类实例

n      抽象类和接口都是用来实现抽象的。

定义如下:

访问修饰符  abstract class 类名

{

抽象类体

}

抽象类定义示例:

publicabstract class Employee

{

protected string nid;

public abstract int GetSalary();

public abstract int Name{get;set;}

}

抽象类的定义和普通类的定义非常相似,只是在class和类的访问修饰符中间加了一个abstract关键字。抽象类面可以定义抽象方法、抽象属性等。抽象类只是用来描述功能,所以这些抽象的方法、属性等不需要去实现它,只写个空壳就可以了。

抽象类的使用

抽象类不能自己实例化,需要使用其子类来实例化。那么抽象实例怎样才能代表子类实例行使子类功能呢?C#中提供了一种重写的机制来完成这个功能。重写关键字为override,子类使用该关键字来重写基类的抽象方法、抽象属性等(注意:凡是子类继承了抽象类,就必须重写抽象类里的抽象方法,否则编译出错)。

/*抽象类案例*/

usingSystem;

abstractclass BuRuDongWu   //抽象类:哺乳动物类

{

//成员变量

protected int legs;

protected BuRuDongWu(int legs)

{

this.legs=legs;

}

//抽象方法

public abstract void eat();

//Console.WriteLine("我有方法体");

//抽象方法做实现了吗?  抽象方法 体现哺乳动物有一个吃的行为就行了,已经代表了所有子类的吃的行为...

//抽象方法没有方法体(不允许有方法体);可以常规方法

public int getLegs()  //常规方法,获得腿数.

{

return legs;

}

}

classDog:BuRuDongWu            //狗类继承自抽象类:哺乳动物类

{

public Dog(int legs):base(legs)

{}

//子类必须实现所有的抽象方法,通过重写.

public override void eat()           //注意,重写方法相当于子类实现了父类的抽象方法

{

Console.WriteLine("狗吃肉");

}

}

classCat:BuRuDongWu

{

public Cat(int legs):base(legs)

{}

public override void eat()           //注意,重写方法相当于子类实现了父类的抽象方法

{

Console.WriteLine("猫吃老鼠");

}

}

classTest

{

static void Main(string[]args)

{

//BuRuDongWu  lv=new BuRuDongWu();    实践证明抽象类不能被实例化;

//抽象类必须被子类继承实现,才能体现功能; --->更好的体现,继承特性;

Dog underDog=new Dog(4);

Cat  lanMao=newCat(4);

underDog.eat();

lanMao.eat();

Console.WriteLine("狗有{0}条腿,猫有{1}条腿",underDog.getLegs(),lanMao.getLegs());

}

}

为什么要使用父类对象指向子类对象实例呢?留给大家思考。

接口—概念、理解、本质

在讲接口概念之前,首先来让我们看一下现实生活中都有哪些是接口。

从现实生活中可以知道,接口是一套规范,遵守这个规范就可以实现功能(比如、用U盘来回拷贝东西、用鼠标操作电脑、用摄像头和电脑建立连接)。

例如,将电器的“开”、“关”行为单独定义为一个接口,这样凡是继承自这个接口的电器就都有了“开”、“关”的方法。让电灯、电视、电扇、电冰箱都继承并实现“开关”接口,这样,对于所有电器来说都有了自己的开关,并且可以针对本身做相应开关的定义。

接口的定义

访问修饰符  interface 接口名   //名称通常以I开头

{

接口内容

}

  1. 与抽象类一样,接口里面的方法成员也不能有方法体;
  2. 类可以继承自接口,继承之后必须实现里面的所有方法;
  3. 接口不能被实例化;
  4. 类在实现接口里的方法的时,不需要使用override关键字,直接实现即可。

5.C#中接口不能包含任何数据成员;

6.接口内的访问修饰符不需要些,默认为public。

//接口示例

using System;

interface OnOff  //开关接口

{

void On();

void Off();

}//实现接口的类必须实现接口的所有成员(成员变量、成员方法....);

class Light:OnOff    //灯

{

public void On()     //Light类继承了OnOff接口,在自己的类中对接口中的2个方法来做实现.

{

Console.WriteLine("电灯亮了");

}

public void Off()

{

Console.WriteLine("电灯关了");

}

}

class TV:OnOff

{

public void On()     //TV类继承了OnOff接口,在自己的类中对接口中的2个方法来做实现.

{

Console.WriteLine("电视亮了");

}

public void Off()

{

Console.WriteLine("电视关了");

}

}

class Test

{

static void Main(string[]args)

{

Light meDeng=new Light();

meDeng.On();

meDeng.Off();

TV meTv=new TV();

meTv.On();

meTv.Off();

}

}

接口的使用基本上和抽象类一样,有人把接口比做双节棍中的一节,另外一节就是继承并实现接口的类,只有两节联合起来使用才会发生效力。

另外,在C#中接口是多继承的,接口之间可以互相继承与多继承、普通类或抽象类也可以继承自接口(注意接口不能继承自类或抽象类),一个类可以同时继承自类和多个接口。

u    接口与接口之间

接口与接口之间可以互相继承,继承的规则和类一样,即子接口将获得父接口的内容。

interface Irun{void run();}    //跑动

interface Iswim{void swim();}   //游泳

interface Itwo:Ifly,Iswim{}    //同时实现跑动与游泳

class TwoTank:Itwo

{       //自己的两栖坦克

public void run(){…}

public void swim(){…}

}

u    接口、抽象类和类

interface IA{void playA{};}

interface IB{void playB{};}

abstract class TC

{

public abstract  void playC();

}

class TD:TC,IA,IB

{…}

面向接口的编程

设计模式的祖师GoF,有句名言:Program to an interface,not an implementation,表示对接口编程而不要对实现编程,更通俗的说法是对抽象编程而不是对具体编程。

微软的FCL(基础类库),是微软的一帮牛人已经定义好了的东西,如果你理解了接口,就会发现FCL类库中使用到了很多接口技术。比如数组Array类:

publicabstractclass Array :ICloneable,

IList,ICollection,IEnumerable

,实现了System.Collections命名空间下的Ienumerable接口,那么我们可以用此数组来操作数组元素:

int []a=new int[]{1,2,3,4,5};

System.Collections.Ienumerator it=a.GetEnumerator();

while(it.MoveNext())

{

Console.WriteLine(it.Current.ToString());

}

抽象类与接口的异同:

实践问题:

选择题:

1.      下面哪个不是类?

小结:

在本章中,我们主要学习了:

u      继承的定义及其使用

u      什么是抽象类及重写

u      接口的定义与使用

英语词汇:

英文            全文                                        中文

Base                            基础的,基类

Derived                         派生的,继承的

Point                           点

Abstract                        抽象的

Virtual                         虚的

Animal                      动物

Sealed                      封装的

Method                      方法

Interface                       接口

Declare                         声明

Update                      更新

Item                              项

Override                        重载

Furniture                       家具

Bookshelf                       书柜

练习项目:

1请编码实现某软件公司员工的继承关系:

雇员(Animal)具有行为:上班、工作、下班

雇员包括:技术员工,客服、销售

这些员工工作的行为各不相同;但上班、下班的行为是一致的。

时间: 2024-10-09 20:32:01

C#OOP之八 继承 接口和抽象类的相关文章

类与接口的继承 接口与抽象类 抽象工厂

为什么Java里面只允许单一继承,但允许实现多个接口? 1,接口可以继承多个接口.为什么不能实现类的多继承?主要是防止多个类有相同的方法名,然而方法体不一样,子类就比较难选择了.所以java和C#不支持类的多继承2,允许具有多个接口的一个好处就是,当实现多个接口时,如果两个接口有同样的方法,那么实现一次就可以了.由于接口没有方法体,所以接口可以实现多继承. 如何间接实现类的多重继承? 1.可以通过继承多个接口实现多重继承. 2.A -> B -> C .

【Java面试题】60 接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象类中是否可以有静态的main方法?

接口可以继承接口.抽象类可以实现(implements)接口,抽象类可以继承具体类.抽象类中可以有静态的main方法. 问:  抽象类是否可继承实体类 (concrete class) 答: 抽象类是可以继承实体类,但前提是实体类必须有明确的构造函数. 答案很明确,可以继承.其实从Object就是个实体类,Java的API文档里,每个抽象类的条目里都明确写着直接或间接继承自Object,所以这点是没有疑问的. 关键在于这答案里所说的"前提是实体类必须有明确的构造函数"一句,是什么意思.

15、接口是否可继承接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concreteclass)?抽象类中是否可以有静态的main方法?

接口可以继承接口.抽象类可以实现(implements)接口,抽象类可以继承具体类.抽象类中可以有静态的main方法. 问:  抽象类是否可继承实体类 (concrete class) 答: 抽象类是可以继承实体类,但前提是实体类必须有明确的构造函数. 答案很明确,可以继承.其实从Object就是个实体类,Java的API文档里,每个抽象类的条目里都明确写着直接或间接继承自Object,所以这点是没有疑问的. 关键在于这答案里所说的“前提是实体类必须有明确的构造函数”一句,是什么意思. 一般学习

JAVAOO 继承~接口 笔记

继承 继承方式:public class 子类  extends 父类 关键字:super super调用父类时必须是第一条语句 继承的优点 代码可重用 子类可以扩展父类的属性和方法.父类的属性和方法可用于子类.设计应用程序变得更简单 所有类的跟类都是Object 方法重写 发生在子类中,对父类重写 1.子类的方法的返回值类型,方法名和形式参数列表 必须和父类中的相同 2.访问修饰符必须不小于父类中的访问修饰符 3.子类中重写的异常不能抛出比父类更多的异常 构造器中子类会默认调用父类的无参构造器

接口和抽象类该什么时候用?

以操作数据库为例:既然是操作数据库就必须会用到 Insert Update Select ,所以Insert Update Select 做成接口 但是,每个功能操作的内容又不一样,所以,做一个抽象类继承接口然后抽象类的派生类去实现抽象类的具体方法 面向对象,就是要把一些代码上的东西当成实体来理解.实体有本身的属性和行为.比如你这个对数据库的操作,你就要把数据库当做一个对象,其行为可以是增删改查.所以你应该声明一个类去进行这些操作.当然,考虑到各种业务的特性,你还可以将这些类抽象出来,声明一个接

[Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类

目录 第一章 对象导论第二章 一切都是对象第三章 操作符第四章 控制执行流程第五章 初始化与清理第六章 访问权限控制第七章 复用类第九章 接口 第一章 对象导论 1. 对象的数据位于何处? 有两种方式在内存中存放对象: (1)为了追求最大的执行速度,对象的存储空间和生命周期可以在编写程序时确定,这可以通过将对象置于堆栈或者静态存储区域内来实现.这种方式牺牲了灵活性. (2)在被称为堆的内存池中动态地创建对象.在这种方式,知道运行时才知道对象需要多少对象,它们的生命周期如何,以及它们的具体类型.

接口、接口优点、接口的属性和方法特性、接口与继承的区别、接口与抽象类的区别、匿名实现类、JDK1.8新特性、打印类名称

接口里的属性,必须是公共的/默认的&静态的&Final&初始化后的属性: 接口里所有方法都是抽象的. 接口和继承---先天有的用继承,后天学习的用接口: 接口特性-------- 1.接口不可以被实例化: 2.实现类必须实现接口中所有方法,否则实现类必须是抽象类 3.实现类可以实现多个接口,来弥补Java不能多继承: 4.接口中的变量都是静态常量:(静态的-可以通过类的名字点-直接调用:) ----------------------------------------------

Python开发基础-Day18继承派生、组合、接口和抽象类

类的继承与派生 经典类和新式类 在python3中,所有类默认继承object,但凡是继承了object类的子类,以及该子类的子类,都称为新式类(在python3中所有的类都是新式类) 没有继承object类的子类成为经典类(在python2中,没有继承object的类,以及它的子类,都是经典类) 1 class People: 2 pass 3 class Animal: 4 pass 5 class Student(People,Animal): #People.Animal称为基类或父类,

python开发面向对象基础:接口类&抽象类&多态&多继承

一,接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能 开发中容易出现的问题 1 class Alipay: 2 ''' 3 支付宝支付 4 ''' 5 def pay(self,money): 6 print('支付宝支付了%s元'%money) 7 8 class Applepay: 9 ''' 1