在c#中,一个类可以继承另外一个已有的类(密封类除外),被继承的类称为基类(或父类),继承的类称为派生类(或子类),子类将获得基类除构造函数和析构函数以外的所有成员。此外,静态类是密封的,也不能被继承。
例如,学生、老师、程序员等都是属于人类,但他们是不同职业的人类,除了具有人类的共同性外,他们还具有各自的特点,如不同的身份、不同的工作方式等。我们可以把人类定义为学生、老师、程序员的父类,这样子类不但继承了基类除构造函数和析构函数以外的所有成员,还可以添加自己特有的成员。
通过继承,程序可实现对父类代码的复用。因为子类可继承父类的所有成员,父类中定义的代码便不需要在子类中进行重复定义了。
代码示例:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp { class Person { private string _name; private char _sex; private int _age; public string Name { get { return _name; } set { _name = value; } } public char Sex { get { return _sex; } set { _sex = value; } } public int Age { get { return _age; } set { _age = value; } } public Person(string name,char sex,int age) { this.Name = name; this.Sex = sex; this.Age = age; Console.WriteLine("我是Person类的构造函数,我被调用了"); } public void SayHello() { Console.WriteLine("大家好!我是人类"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp { class Student: Person //Student类继承Person类 { private int stuId; //学号 private double score; //分数 public Student(string name,char sex ,int age, int stuId, double score) : base(name, sex, age) { this.StuId = stuId; this.Score = score; Console.WriteLine("我是Student类的构造函数,我被调用了"); } public int StuId { get { return stuId; } set { stuId = value; } } public double Score { get { return score; } set { score = value; } } public void study() { Console.WriteLine("我是一名学生,我要学习各门功课。"); } //使用关键字new隐藏父类成员。new创建对象后,隐藏从父类那里继承过来的同名成员。隐藏的后果就是子类调用不到父类的成员,所以尽量不要把子类成员名写得跟父类一样。 public new void SayHello() { Console.WriteLine("大家好!我是学生类"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp { class Teacher: Person //Teacher类继承Person类 { private int jobId; //教工号 private double salary; //薪水 public Teacher(string name, char sex, int age, int jobId, double salary) : base(name, sex, age) { this.JobId = jobId; this.Salary = salary; Console.WriteLine("我是Teacher类的构造函数,我被调用了"); } public int JobId { get { return jobId; } set { jobId = value; } } public double Salary { get { return salary; } set { salary = value; } } public void work() { Console.WriteLine("我是老师,我的工作内容是教书。"); } //使用关键字new隐藏父类成员。new创建对象后,隐藏从父类那里继承过来的同名成员。隐藏的后果就是子类调用不到父类的成员,所以尽量不要把子类成员名写得跟父类一样。 public new void SayHello() { Console.WriteLine("大家好!我是教师类"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp { class Program { static void Main(string[] args) { Student stu = new Student("盛婷婷",'女',18,1001,98.5); Console.WriteLine("姓名:{0},性别:{1},年龄:{2},学号:{3},成绩:{4}",stu.Name,stu.Sex,stu.Age,stu.StuId,stu.Score); stu.study(); stu.SayHello(); //如果此时仍然想访问基类的成员,则可以使用强制类型转换,把子类强制转换成基类,从而访问隐藏的基类成员。 //((Person)stu).SayHello(); //输出了 大家好!我是人类 Teacher tea = new Teacher("陈大文", '男', 40, 32, 6500); Console.WriteLine("姓名:{0},性别:{1},年龄:{2},教工号:{3},工资:{4}", tea.Name, tea.Sex, tea.Age, tea.JobId, tea.Salary); tea.work(); tea.SayHello(); Console.ReadKey(); } } }
运行结果:
类图
查看类图:解决方法资源管理器-->项目-->右键-->查看-->查看类图
总结:
继承:父类(基类)、子类(派生类)
我们可能会在一些类中,写一些重复的成员,我们可以将这些重复的成员,单独的封装到一个类中,作为这些类的父类。
继承的特性:
(1)、继承的单根性:一个子类只能继承一个父类,不能同时继承多个父类。C#中,派生类只能从一个类中继承。C#不支持多重继承,通俗的说就是儿子只能有一个亲生父亲,不能同时拥有多个亲生父亲。C#可以继承多个接口。
(2)、继承的传递性:派生类从基类那里继承特性。派生类也可以作为其它类的基类。从一个基类派生出来的多层类形成了类的层次结构。通俗的说就是爷爷、爸爸、儿子的关系,儿子能访问爸爸、爷爷的公有成员,爸爸能访问爷爷的公有成员但不能访问儿子的公有成员。
class A
{
}
class B : A
{
}
//A是基类,B是派生类,一个类最多只允许从一个类中派生。
class C : B
{
}
//C还能继承B,充当B的派生类。
问:子类继承了父类,那么子类从父类那里继承过来了什么?
答:子类继承了父类的属性和方法,但子类并没有继承父类的私有字段。
问:子类有没有继承父类的构造函数和析构函数?
答:子类并没有继承父类的构造函数和析构函数,但是子类会默认的调用父类无参数的构造函数(用来创建父类对象,让子类可以使用父类中的成员。)所以如果在父类写了一个有参数的构造函数之后,那个默认的无参数的构造函数就被干掉了,因此子类就调用不到了,所以子类会报错。
解决方法:
方法一:在父类重新写一个无参数的构造函数。
方法二:一般都采用这种方法,在子类用显式的调用父类的构造函数,使用关键字 :base() 去调用父类的构造函数。
new关键字用途:
(1)、创建对象。
(2)、使用关键字new隐藏父类成员。new创建对象后,隐藏从父类那里继承过来的同名成员。隐藏的后果就是子类调用不到父类的成员,所以尽量不要把子类成员名写得跟父类一样。如果此时仍然想访问基类的成员,则可以使用强制类型转换,把子类强制转换成基类,从而访问隐藏的基类成员。例如:((Person)stu).SayHello();
子类的初始化顺序:
使用了继承之后,当我们初始化一个子类时,除了会调用子类的构造函数外,同时也会调用基类的构造函数。子类的初始化顺序如下:
(1)、初始化类的实例字段。
(2)、调用基类的构造函数,如果没有指明基类,则调用System.Object的构造函数。
(3)、调用子类的构造函数。
所有类的父类:System.Object
在C#中,所有的类都直接或间接继承System.Object类,如果定义的类没有指定任何基类,编译器就会自动把System.Object类当作它的基类。和其他类一样,System.Object类也定义了一组共有的成员,其定义如下:
public class Object { //方法 //构造函数 public Object(); //虚成员 public virtual bool Equals(object obj); protected virtual void Finalze(); public virtual int GetHashCode(); public virtual string ToString(); //实例成员 public Type GetType(); protected Object MemberwiseClone(); //静态成员 public static bool Equals(Object objA, Object objB); public static bool ReferenceEquals(Object objA, Object objB); }
文章评论