[.net 面向对象编程基础] (15) 抽象类
[.net 面向对象编程基础] (15) 抽象类
前面我们已经使用到了虚方法(使用 Virtual修饰符)和抽象类及抽象方法(使用abstract修饰符)我们在多态一节中说到要实现类成员的重写必须定义为一个虚方法或抽象方法。这节单独把抽象类提出来,是因为抽象是.net实现面向对象编程重要的重要思想,定义抽象类就象一个模板一个提纲,它可以理解为中央的指导思想,我们通过派生类去具体实现它。由此可见,抽象类本身没有任何作用,也不能被实例化,因为他本身就不具有具体的事物。比如上节的动物类的例 子,我们实例化一个动物类并没有意义,我们需要实例的类是具体的动物,比如Dog、Cat、Sheep这些。
而我们使用面向对象编程,就要在具体的应用过程中,学会抽象出事物的共同点,形成一个基类,其它类去继承他,实现他。为我们提高编程、学习设计模式很有益处。
1.什么是抽象类
如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个基类,这样的类就是抽象类,在抽象类中声明方法时,如果加上abstract时就是抽象方法
1.抽象类的声明
抽象类使用abstract 关键词进行声明。
2.抽象类的特点:
A.抽象类不能被实例化
B.抽象类是一种特殊的类,具有类的特性,其成员可以是抽象的,也可以不是抽象的。
C.抽象方法必须定义在抽象类中,而不能定义在非抽象类中
D.抽象类可以继承一个抽象类,其派生类仍然是一个抽象类
E.抽象类不能被密封(不能使用sealed(sealed指该类不可被继承))
3.抽象方法的特点:
A.抽象方法是隐式的虚方法
B.抽象方法只允许声明在抽象类中
C.抽象方法不能提供实际的实现,所以没有方法体;抽象方法的实现是在非抽象的派生类中以override重写实现的
D.抽象方法声明中不可以使用static或者virtual修饰符
E.abstract关键字不能修饰静态方法或静态属性
6.抽象类的构造函数
A.不要再抽象类中定义public或protected internal访问权限的构造函数
B.应在抽象类中定义protected或private访问权限的构造函数
C.如果在抽象类中定义一个protected构造函数,则在实例化派生类时,基类可以执行初始化任务
7.抽象方法和虚方法的区别
虚方法(使用Virtual修饰符)有实现部分,并且派生类对其重写是可选的;抽象方法没有实现部分,并且强制非抽象派生类对其重写
8.抽象类和接口的区别
其实这个区别,本来是要在下一节,接口中讲的,在这里提前说一下,有点印象也好。
A.它们的派生类只能继承一个基类,即只能继承一个抽象类,但是可以继承多个接口。
B.抽象类中可以定义成员的实现,但接口中不可以。
C.抽象类中包含字段、构造函数、析构函数、静态成员或常量等,接口中不可以。
D.抽象类中的成员可以私有的(只要不是抽象的)、受保护的、内部的或受保护的内部成员,但接口中的成员必须是公共的。
PS:抽象类和接口这两种类型用于完全不同的目的。抽象类主要用作对象系列的基类,共享某些主要特性,例如共同的目的和结构。接口则主要用于类,这些类在基础水平上有所不同,但仍然可以完成某些相同的任务。
7. 举例
我们举一个例子来说明一下抽象类的使用,还是我们前面的例子,基类动物(Animal),我们定义成一个抽象类,有几个派生类狗、猫、羊,假如我们猫还有波斯猫,狗还有牧羊犬,那么我们还可以让它们再次继承,因为猫和狗本身也是动物,我们可以不定义为抽象类,让他们支持实例化。下面看一下UML图:

关于UML图我会在后面抽时间写的,里面的成员+表示公有,-表示私有,字段、属性、方法使用分割线
下面是具体实现代码:
/// <summary>
/// 动物类(父类 抽象类)
/// </summary>
abstract class Animal
{
/// <summary>
/// 名字
/// 说明:类和子类可访问
/// </summary>
protected string name; /// <summary>
/// 构造函数
/// </summary>
/// <param name="name"></param>
public Animal(string name)
{
this.name = name;
} private int shoutNum = ;
public int ShoutNum
{
get { return shoutNum; }
set { shoutNum = value; }
} /// <summary>
/// 名字(虚属性)
/// </summary>
public virtual string MyName
{
get { return this.name; } } /// <summary>
/// 叫声,这个方法去掉虚方法,把循环写在这里
/// </summary>
public void Shout()
{
string result = "";
for (int i = ; i < ShoutNum; i++)
result += getShoutSound()+"!"; Console.WriteLine(MyName);
Console.WriteLine(result);
} /// <summary>
/// 创建一个叫声的虚方法,子类重写
/// </summary>
/// <returns></returns>
public virtual string getShoutSound()
{
return "";
} } /// <summary>
/// 狗(子类)
/// </summary>
class Dog : Animal
{
string myName;
public Dog(string name)
: base(name)
{
myName = name;
} /// <summary>
/// 名字(重写父类属性)
/// </summary>
public override string MyName
{
get { return "我是:狗狗,我叫:" + this.name; }
} /// <summary>
/// 叫(重写父类方法)
/// </summary>
public override string getShoutSound()
{
return "汪!";
}
} /// <summary>
/// 狗(子类)
/// </summary>
class ShepherdDog : Dog
{
string myName;
public ShepherdDog(string name): base(name)
{
myName = name;
} /// <summary>
/// 名字(重写父类属性)
/// </summary>
public override string MyName
{
get { return "我是:牧羊犬,我叫:" + this.name; }
} /// <summary>
/// 叫(重写父类方法)
/// </summary>
public override string getShoutSound()
{
return "汪~呜!";
}
} /// <summary>
/// 猫(子类)
/// </summary>
class Cat : Animal
{
string myName;
public Cat(string name)
: base(name)
{
myName = name;
}
/// <summary>
/// 名字(重写父类属性)
/// </summary>
public override string MyName
{
get { return "我是:猫咪,我叫:" + this.name; } } /// <summary>
/// 叫(重写父类方法)
/// </summary>
public override string getShoutSound()
{
return "喵!";
}
} /// <summary>
/// 猫(子类)
/// </summary>
class PersianCat : Cat
{
string myName;
public PersianCat(string name): base(name)
{
myName = name;
}
/// <summary>
/// 名字(重写父类属性)
/// </summary>
public override string MyName
{
get { return "我是:波斯猫,我叫:" + this.name; } } /// <summary>
/// 叫(重写父类方法)
/// </summary>
public override string getShoutSound()
{
return "喵~呜!";
}
} /// <summary>
/// 羊(子类)
/// </summary>
class Sheep : Animal
{
string myName;
public Sheep(string name)
: base(name)
{
myName = name;
}
/// <summary>
/// 名字(重写父类属性)
/// </summary>
public override string MyName
{
get { return "我是:羊羊,我叫:" + this.name; } }
/// <summary>
/// 叫(重写父类方法)
/// </summary>
public override string getShoutSound()
{
return "咩!";
}
}
调用及结果如下:
//调用
Animal persianCat = new PersianCat("好猫");
persianCat.Shout();
Console.ReadLine();
//结果如下:
//我是:波斯猫,我叫:好猫
//喵~呜!!喵~呜!!喵~呜!!
10要点:
抽象类是指:一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个基类。
抽象类是一种特殊类,使用abstract声明
抽象类不可被实例化
抽象类可以继承一个抽象类
抽象方法只能存在于抽象类中,可以和虚方法一样,在派生类中重写。
抽象类的存在就是被继承用的,因此不允许被密封(即不能使用sealed修饰)
最后,抽象,是面向对象程序设计的重要思想。。
==============================================================================================
返回目录 <如果对你有帮助,记得点一下推荐哦,有不明白的地方或写的不对的地方,请多交流>
==============================================================================================
[.net 面向对象编程基础] (15) 抽象类的更多相关文章
- [.net 面向对象编程基础] (1) 开篇
[.net 面向对象编程基础] (1)开篇 使用.net进行面向对象编程也有好长一段时间了,整天都忙于赶项目,完成项目任务之中.最近偶有闲暇,看了项目组中的同学写的代码,感慨颇深.感觉除了定义个类,就 ...
- 大数据技术之_16_Scala学习_04_函数式编程-基础+面向对象编程-基础
第五章 函数式编程-基础5.1 函数式编程内容说明5.1.1 函数式编程内容5.1.2 函数式编程授课顺序5.2 函数式编程介绍5.2.1 几个概念的说明5.2.2 方法.函数.函数式编程和面向对象编 ...
- [.net 面向对象编程基础] (3) 基础中的基础——数据类型
[.net 面向对象编程基础] (3) 基础中的基础——数据类型 关于数据类型,这是基础中的基础. 基础..基础..基础.基本功必须要扎实. 首先,从使用电脑开始,再到编程,电脑要存储数据,就要按类型 ...
- [.net 面向对象编程基础] (8) 基础中的基础——修饰符
[.net 面向对象编程基础] (8) 基础中的基础——修饰符 在进入C#面向对象核心之前,我们需要先对修饰符有所了解,其实我们在前面说到变量和常量的时候,已经使用了修饰符,并且说明了变量和常量的修改 ...
- [.net 面向对象编程基础] (10) 类的成员(字段、属性、方法)
[.net 面向对象编程基础] (10) 类的成员(字段.属性.方法) 前面定义的Person的类,里面的成员包括:字段.属性.方法.事件等,此外,前面说的嵌套类也是类的成员. a.类的成员为分:静态 ...
- [.net 面向对象编程基础] (16) 接口
[.net 面向对象编程基础] (16) 接口 关于“接口”一词,跟我们平常看到的电脑的硬件“接口”意义上是差不多的.拿一台电脑来说,我们从外面,可以看到他的USB接口,COM接口等,那么这些接口的目 ...
- [.net 面向对象编程基础] (17) 数组与集合
[.net 面向对象编程基础] (17) 数组与集合 学习了前面的C#三大特性,及接口,抽象类这些相对抽象的东西以后,是不是有点很累的感觉.具体的东西总是容易理解,因此我们在介绍前面抽象概念的时候,总 ...
- [.net 面向对象编程基础] (18) 泛型
[.net 面向对象编程基础] (18) 泛型 上一节我们说到了两种数据类型数组和集合,数组是指包含同一类型的多个元素,集合是指.net中提供数据存储和检索的专用类. 数组使用前需要先指定大小,并且检 ...
- [.net 面向对象编程基础] (20) LINQ使用
[.net 面向对象编程基础] (20) LINQ使用 通过上节LINQ的基础知识的学习,我们可以开始使用LINQ来进行内存数据的查询了,我们上节说了LINQ的定义为:Language Integr ...
随机推荐
- Ceph剖析:Paxos算法实现
作者:吴香伟 发表于 2014/10/8 版权声明:可以任意转载,转载时务必以超链接形式标明文章原始出处和作者信息以及版权声明 Recovery阶段 在Leader选举成功后,Leader和Peon都 ...
- final、finally、finalize的区别
看C#知识点的时候发现的问题 1.final 修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承.因此一个类不能既被声明为 abstract的,又被声明为f ...
- 【转】Crontab定时任务配置
原文出处:http://www.cnblogs.com/kerrycode/p/3238346.html CRONTAB概念/介绍 crontab命令用于设置周期性被执行的指令.该命令从标准输入设备读 ...
- AndroidLinker与SO加壳技术之下篇
点此查看上篇<AndroidLinker与SO加壳技术之上篇> 2.4 链接 链接过程由 soinfo_link_image 函数完成,主要可以分为四个主要步骤: 1. 定位 dynami ...
- 二 Java利用等待/通知机制实现一个线程池
接着上一篇博客的 一Java线程的等待/通知模型 ,没有看过的建议先看一下.下面我们用等待通知机制来实现一个线程池 线程的任务就以打印一行文本来模拟耗时的任务.主要代码如下: 1 定义一个任务的接口 ...
- STL 跨模块 调用 异常 解决
本文为转载别人的,以作收藏之用 百度了一天,现在把结论放上边: 1.不要用STL(std::string属于STL)来跨模块传输数据,例如:dll(so)之间,dll(so)和exe(elf)之间. ...
- Entity Framework 6, database-first with Oracle
Entity Framework 6, database-first with Oracle 转载自http://csharp.today/entity-framework-6-database-fi ...
- GDI+ 发生一般性错误解决办法
错误的代码g对象继续占用 未释放资源 如果路径不一样 没问题 相同路径 获取图片进行 缩略会造成GDI错误 /// <summary> /// 生成缩略图 /// </summary ...
- EM最大期望化算法
最大期望算法(Expectation-maximization algorithm,又译期望最大化算法)在统计中被用于寻找,依赖于不可观察的隐性变量的概率模型中,参数的最大似然估计. 在统计计算中,最 ...
- 【Mail】telnet收发邮件过程
telnet发送邮件 关于电子邮件的基础知识请参照:[Mail]邮件的基础知识和原理 smtp协议是一个简单的邮件传输协议,利用它我们可以将邮件发送给别人,这里将通过telnet这个程序利用smtp协 ...