C#类继承
1、继承的基础
【1】继承的概念
比如:类A---->类B。此时是类B继承自类A,类A就是“父类”,类B就是“子类”。特性:继承具有“单根性”,即一个类只能有一个父类。(不能同时继承多个类、反向继承、循环继承)继承使用的方向:①、代码的复用。②、继承多态的实现。
【2】基本语法
<访问修饰符> class <父类>
{
}
<访问修饰符> class <子类>:<父类>
{
}
【3】构造方法的使用
父类有无参数构造方法当子类构造方法没有明确写调用父类哪个构造方法时,默认调用父类的无参数构造方法。
父类没有无参构造方法子类构造方法必须显式的说明调用父类的哪个有参的构造方法。
▲调用父类的构造方法,请使用base关键字。
【4】protected关键字
在父类外,无法通过“对象”的方式来使用protected修饰的成员,它是受保护的。
在子类外,也无法通过“对象”的方式来使用父类中protected修饰的成员。
总结:使用protected关键字修饰的成员,只能在父类内部和子类内部使用,不能通过“外部”,也就是对象的方法去调用。
【5】父类private修饰的成员
父类中有“private”修饰的成员,如下:Personal:父类。Teacher:子类。
public Personal(string post)
{
this.post = post;
}
//父类使用private修饰的成员
private string post;
public Teacher(string name, string post):base(post)
{
base.Name = name;
}
static void Test2()
{
Teacher teacher = new Teacher("张老师", "高级讲师");
//子类对象在不能直接调用父类的private修饰的成员,也无法通过智能提示看到。
teacher.GetPost();
}
总结:父类中使用private关键字修饰的成员变量,子类对象是不能直接进行调用,以及智能提示也不会显示出来。但是父类的所有成员(包括private修饰的成员),其实都被子类继承过来了。
2、抽象方法(abstract)
【1】抽象方法的概念
在一个类有abstract修饰(抽象类),存在方法的形式为:方法返回值前有abstract关键字修饰,并且没有方法体的方法,叫做抽象方法。
语法格式:public abstract 返回值类型 方法名称();
注意:抽象方法与普通方法只是多了“abstract”修饰词,以及没有方法体。其他都与普通方法一致。
【2】为什么使用抽象方法
在团队合作中,为了更好的约束子类必须要完成父类的某个方法的实现,所有引入了抽象方法的概念,如果没有抽象方法在父类中约束,子类可以实现这个方法,也可以不实现。无法控制。
注意:抽象方法,必须在抽象类中。因为不加abstract修饰的类(抽象类),是可以被实例化的。而抽象方法是没有方法体,不能够被实例化。所有抽象方法必须要在抽象类中。【抽象类直接实例化(new)】。
【3】子类实现抽象方法
父类创建抽象方法Have。不允许编写具体的方法体。
//父类
public abstract class Animal
{
public int Age { get; set; }
public string Name { get; set; }
public string Color { get; set; }
//抽象方法,子类实现该方法
public abstract void Have();
}
因为子类不是抽象类,所有需要使用override关键字重写父类的抽象方法Have。
public class Dog : Animal
{
//子类Dog重写父类的抽象方法。
public override void Have()
{
Console.WriteLine("小狗吃骨头!");
}
}
Cat子类是抽象类,所有可以不重写父类的抽象方法。
//子类Cat
//因为子类为抽象类,所有子类可以不重写父类的抽象方法。
public abstract class Cat:Animal
{
}
总结:子类必须要实现父类的抽象方法(override关键字)。除非子类也是抽象类,那么子类可以不实现父类的抽象方法。也就是子类作为抽象类,把自己的抽象方法和父类抽象方法,让下一级的子类去实现。
3、继承多态
【1】多态的理解
多态是同一种行为具有多个不同的表现形式或形态的行为。
理解1:一种行为,多种实现。
理解2:同一种抽象方法,不同的子类实现,由父类变量去调用。
父类 父类对象 = new 子类();//父类
public abstract class Animal
{
public int Age { get; set; }
public string Name { get; set; }
public string Color { get; set; }
//抽象方法,子类实现该方法
public abstract void Have();
}
//子类Dog重写父类的抽象方法。
public override void Have()
{
Console.WriteLine("小狗吃骨头!");
}
//子类Cat
public class Cat : Animal
{
public override void Have()
{
Console.WriteLine("小猫吃小鱼!");
}
}
static void Test2()
{
//同一中抽象方法,不同的子类去实现,由父类变量调用。
Animal animal = new Dog();
animal.Have();
animal = new Cat();
animal.Have();
}
【2】继承多态的两种实现形式
1、父类作为方法的返回值。
编写一个获取子类对象的方法,方法的返回值类型为父类。在使用时可以根据需要的修改封装的子类对象,而不需要修改调用处的代码。
static void Test3()
{
//将子类对象做一个封装(子类对象可以根据需要,在GetAnimal方法中修改返回的子类对象),
//此处不需要再修改代码。
Animal animal = GetAnimal();
animal.Have();
}
/// <summary>
/// 父类作为方法的返回值
/// </summary>
/// <returns></returns>
static Animal GetAnimal()
{
return new Cat();
}
2、父类作为方法的参数。
父类作为方法的参数类型封装起来,再根据实际的业务,调用方法时传递的时子类的对象。
static void Test3()
{
//将子类对象做一个封装(子类对象可以根据需要,在GetAnimal方法中修改返回的子类对象),
//此处不需要再修改代码。
Animal animal = GetAnimal();
animal.Have();
Console.WriteLine("----------------------------------------");
//父类作为方法的参数
//调用方法时,是更具需要参数是子类对象。
Test(new Cat());
Test(new Dog());
}
/// <summary>
/// 【1】父类作为方法的返回值
/// </summary>
/// <returns></returns>
static Animal GetAnimal()
{
return new Cat();
}
/// <summary>
/// 【2】父类作为方法的参数
/// </summary>
/// <param name="animal"></param>
static void Test(Animal animal)
{
animal.Have();
}
4、虚方法(virtual)
【1】虚方法的理解
虚方法的关键字virtual,其他与普通方法一致。
虚方法要求在父类中,必须有“默认”的方法实现。但是不要求子类是否需要实现该虚方法。
/// <summary>
/// 虚方法:父类创建虚方法,必须对该方法有默认实现。
/// 但不强调子类是否实现虚方法。
/// </summary>
public virtual void Play()
{
Console.WriteLine("动物一般都喜欢奔跑!");
}
【2】虚方法的使用
不强制子类必须实现。
子类重写父类虚方法时,可以使用父类的虚方法,也可以使用自己重写的新方法。
虚方法,也是可以实现继承多态的。
public override void Play()
{
base.Play();//默认调用父类的虚方法的实现
//子类可以重写子类的虚方法
Console.WriteLine("小猫喜欢太阳下睡觉!");
}
Dog子类没有实现父类的虚方法。
public class Dog : Animal
{
//子类Dog重写父类的抽象方法。
public override void Have()
{
Console.WriteLine("小狗吃骨头!");
}
}
static void Test3()
{
//将子类对象做一个封装(子类对象可以根据需要,在GetAnimal方法中修改返回的子类对象),
//此处不需要再修改代码。
Animal animal = GetAnimal();
animal.Have();
Console.WriteLine("----------------------------------------");
//父类作为方法的参数
//调用方法时,是更具需要参数是子类对象。
Test(new Cat());
Test(new Dog());
Console.WriteLine("----------------------------------------");
//虚方法的调用
TestTT(new Cat());
TestTT(new Dog());
}
static void TestTT(Animal animal)
{
animal.Play();
}
5、抽象方法与虚方法的选择
如果不需要父类有默认的方法实现,则选择使用抽象方法。需要父类有默认的方法体,则选择虚方法。