继承和多态、sealed关键字
继承
继承概念
- 继承:通过继承,可以创建新的类,以便重用、扩展和修改其他类中定义的行为。被继承的类称为“基类”,继承它的类称为“派生类”。
- 限制:类只能被单一继承,但接口可以被多重继承。
- 特点:可传递。
注意点
- 基类中的初始化,由于继承了基类的成员变量和成员方法,因此父类对象应在子类对象创建之前被创建。
namespace Blog1
{
class Program
{
public class People
{
protected string name;
public People(string name)
{
this.name = name;
Console.WriteLine("People"+name+"初始化");
}
public void GetName()
{
Console.WriteLine(name);
}
}
public class Student: People
{
//子类的初始化函数写法
public Student(string name):base(name)
{
this.name = "学生"+name;
Console.WriteLine("Student" + name + "初始化");
}
}
public class Minitor : Student
{
public Minitor(string name) : base(name)
{
this.name = "班长" + name;
Console.WriteLine("Minitor" + name + "初始化");
}
}
static void Main(string[] args)
{
People people = new People("小明");
people.GetName();
Student student = new Student("小华");
student.GetName();
Minitor minitor = new Minitor("小红");
minitor.GetName();
Console.ReadKey();
}
}
}
/*输出:
People小明初始化
小明
People小华初始化
Student小华初始化
学生小华
People小红初始化
Student小红初始化
Minitor小红初始化
班长小红
*/
- 多重继承示范。
namespace Blog1
{
class Program
{
public class People
{
protected string name;
public People(string name)
{
this.name = name;
Console.WriteLine("People"+name+"初始化");
}
public void GetName()
{
Console.WriteLine(name);
}
}
// 接口:交学费
public interface Tuition
{
void PayTuition();
}
public class Student: People, Tuition
{
public void PayTuition()
{
Console.WriteLine(name+"交学费");
}
public Student(string name):base(name)
{
this.name = "学生"+name;
Console.WriteLine("Student" + name + "初始化");
}
}
static void Main(string[] args)
{
People people = new People("小明");
people.GetName();
Student student = new Student("小华");
student.GetName();
student.PayTuition();
Console.ReadKey();
}
}
}
/*输出:
People小明初始化
小明
People小华初始化
Student小华初始化
学生小华
学生小华交学费
*/
多态
- 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。
1.重载(Overload)
- 重载:重新加载的意思,同一个类中有同名称但是参数列表不同的方法。
- 条件:没有关键字,但必须在同一个类里面,利用参数不同来重写同名称的方法(只是返回值不同不能做区分)。
namespace Blog1
{
class Program
{
public class People
{
protected string name;
public People(string name)
{
this.name = name;
}
public void Drive()
{
Console.WriteLine(name+"开车");
}
public void Drive(string car_name)
{
Console.WriteLine(name + "开"+car_name);
}
}
static void Main(string[] args)
{
People people = new People("小明");
people.Drive();
people.Drive("法拉利");
Console.ReadKey();
}
}
}
/*输出:
小明开车
小明开法拉利
*/
2. 重写(Override)
- 重写:子类重写父类的方法,重写会改变父类方法的功能。
- 条件:重写父类的方法必须是虚方法(virtual)、抽象方法(abstract)、重写方法(override)。而且重写方法的名称、参数、返回值都要相同。
- 格式:子类重写的方法前面加上override关键字修饰。
虚方法(virtual)
虚方法:基类将方法声明为 virtual 时,派生类可以使用其自己的实现override该方法。
namespace Blog1
{
class Program
{
public class People
{
public virtual void Eat()
{
Console.WriteLine("吃饭");
}
}
public class Student : People
{
public override void Eat()
{
//可以用base.Eat();来调用父类原本的Eat方法
Console.WriteLine("在学校食堂");
//base.Eat();
}
}
static void Main(string[] args)
{
People p0 = new People();
p0.Eat();
Student s0 = new Student();
s0.Eat();
//重写会改变父类方法的功能
People p1 = new Student();
p1.Eat();
Console.ReadKey();
}
}
}
/*输出:
吃饭
在学校食堂
在学校食堂
*/
抽象方法(abstract)
抽象方法:如果基类将成员声明为 abstract,则必须在直接继承自该类的任何非抽象类中重写该方法。 如果派生类本身是抽象的,则它会继承抽象成员而不会实现它们。
namespace Blog1
{
class Program
{
public abstract class People
{
public abstract void Eat();
}
public class Student : People
{
public override void Eat()
{
Console.WriteLine("在学校食堂吃饭");
}
}
static void Main(string[] args)
{
Student s0 = new Student();
s0.Eat();
People p1 = new Student();
p1.Eat();
Console.ReadKey();
}
}
}
/*输出:
在学校食堂吃饭
在学校食堂吃饭
*/
抽象方法和虚方法的区别
抽象方法和虚方法的区别:
- 虚方法有方法体,抽象方法没有方法体。
- 抽象方法只能在抽象类中声明,虚方法不用。
- 抽象方法必须在直接继承自该类中重写方法,如果派生类是抽象则不会重写。而虚方法不一定用重写覆盖方法。
3. 覆盖/隐藏
- 覆盖(new):覆盖又称为隐藏,只是隐藏了父类中相同名称的方法,没有进行重写。
- 条件:通过new方法修饰派生类中与基类有相同名称和参数声明成员来隐藏基类成员(返回值没关系),并在方法前加上new关键字。如果和原方法的参数不同,就相当于重载了。
namespace Blog1
{
class Program
{
public class People
{
//这个可以用virtual修饰也可以不用
public virtual void Eat()
{
Console.WriteLine("吃饭");
}
}
public class Student : People
{
public new void Eat()
{
//可以用base.Eat();来调用父类原本的Eat方法
Console.WriteLine("在学校食堂");
//base.Eat();
}
}
static void Main(string[] args)
{
People p0 = new People();
p0.Eat();
Student s0 = new Student();
s0.Eat();
//覆盖不会改变父类方法的功能
People p1 = new Student();
p1.Eat();
Console.ReadKey();
}
}
}
/*输出:
吃饭
在学校食堂
吃饭
*/
4. 三者区别
- 重写会改变父类方法的功能,但覆盖不会改变父类方法的功能。
- 重载是在同一个类里面,覆盖和重写是引用在子类和父类。
- 可以覆盖/隐藏虚方法和非虚方法。
sealed关键字
- sealed修饰类:又称为密封类,用sealed关键字修饰类,让类不能被继承。
- sealed修饰方法或者属性:能够允许类从基类继承,并防止它们重写特定的虚方法或虚属性。但是要注意sealed是对虚方法或虚属性,也就是同override一起使用,不然会报错的。