C#面向对象多态

多态

1.装箱和拆箱

  • 概念: 

装箱:将值类型转换成引用类型的过程

拆箱:将引用类型转换成值类型的过程

例如:使用ArrayList集合时就经常会用到装箱的过程

int n = 10;
object o = n;//这个就是装箱的过程
int nn = (int)o;//这个就是拆箱的过程
  • 注意: 

 判断有没有装箱和拆箱的操作时,要看这两种类型有没有继承关系,有继承关系有可能有装箱和拆箱的操作,没继承关系就不可能有装箱拆箱的操作。

//没有发生拆箱的操作
string str = "123";
int n = Convert.ToInt32(str);//string类型虽说是引用类型,但是两者没有继承关系。

//装箱的操作
int n = 10;
IComparable i = n;//这两个数据类型有继承关系

 2.多态

  • 概念:

 让一个对象能表现出多种状态或者类型。

注意:使用多态时,需要让对象继承。 

  • 实现多态的方法: 

1.虚方法

2.抽象类

3.接口 

2.1 虚方法

  • 步骤: 

1.使用关键字virtual标记父类中的方法,表示这个方法可以被子类重写。

2.使用override关键字标记子类的方法,表示子类可以重写父类的方法。

//类
public class Person
{
    string name;
    public Person(string name)
    {
        this.name = name;
    }
    public virtual void SayHello()
    {
        Console.WriteLine("我是人类");
    }
}
public class Chinese : Person
{
    public Chinese(string name) : base(name)
    {
 
    }
    public override void SayHello()
    {
        Console.WriteLine("我是中国人,我叫{0}", this.Name);
    }
}
public class Japanese : Person
{
    public Japanese(string name) : base(name)
    {
 
    }
    public override void SayHello()
    {
        Console.WriteLine("我是日本人,我叫{0}", this.Name);
    }
}
public class Korean : Person
{
    public Korean(string name) : base(name)
    {
 
    }
    public override void SayHello()
    {
        Console.WriteLine("我是韩国人,我叫{0}", this.Name);
    }
}
public class American : Person
{
    public American(string name) : base(name)
    {
 
    }
    public override void SayHello()
    {
        Console.WriteLine("我是美国人,我叫{0}", this.Name);
    }
}
//主函数
Chinese cn1 = new Chinese("韩梅梅");
Chinese cn2 = new Chinese("李雷");
Japanese j1 = new Japanese("树下君");
Japanese j2 = new Japanese("井边子");
Korean k1 = new Korean("金秀贤");
Korean k2 = new Korean("金贤秀");
American a1 = new American("科比布莱恩特");
American a2 = new American("奥尼尔");
//建立父类数组,子类可以赋值给父类
Person[] pers = { cn1, cn2, j1, j2, k1, k2, a1, a2 };
for (int i = 0; i < pers.Length; i++)
{
    //    if(pers[i]is Chinese)
    //    {
    //        ((Chinese)pers[i]).SayHello();
    //    }
    //    else if(pers[i] is Japanese)
    //    {
    //        ((Japanese)pers[i]).SayHello();
    //    }
    //    else if(pers[i] is Korea)
    //    {
    //        ((Korea)pers[i]).SayHello();
    //    }
    //    else
    //    {
    //        ((American)pers[i]).SayHello();
    //    }
    //如果我们使用多态,就能省略掉这么多代码。
    pers[i].SayHello();
}

注意:当使用pers[i].SayHello()的时候,他会根据存在数组的对象类型来寻找所要输出的语句,来代替掉父类的SayHello()方法。 

2.2 抽象类

  • 概念: 

当父类中的方法不知道该怎么实现时,可以考虑将父类写成抽象类。

  • 方法: 

abstract关键字来标记一个类是抽象类,同样用abstruct关键字来标记一个方法是抽象方法,但是这个抽象方法没有方法体。 

注意:

1.抽象成员必须标记为abstract,并且不能有任何实现

2.抽象成员必须在抽象类中

3.抽象类不能被实例化(因为这个类如果实例化,并不能调用到自己的任何成员,没有意义。)

 4.子类继承抽象类后,必须把父类中的所有抽象成员都重写(除非子类也是一个抽象类,可以不重写)

5.抽象成员的访问修饰符不能是private(如果是private,子类就不能访问到该方法,也就不能实现)

6.在抽象类中可以包含实例成员,并且抽象类的实例成员可以不被子类实现(虽然自己用不了但是子类都可以继承)

7.抽象类是有构造函数的,虽然不能被实例化。

8.如果父类的抽象方法中有参数,那么继承这个抽象父类的子类在重写父类的方法的时候,必须传入相对应的参数。如果抽象父类的抽象方法中有返回值,那么子类在重写这个抽象方法的时候也必须有返回值。

//类
public abstract class Animal
{
    public abstract void Bark();
}
public class Dog : Animal
{    
    public override void Bark()
    {
        Console.WriteLine("狗狗汪汪的叫");
    }
}
public class Cat : Animal
{
    public override void Bark()
    {
        Console.WriteLine("猫咪喵喵的叫");
    }
}
//主函数
Animal a = new Dog();
a.Bark();
Console.ReadKey();

2.3 接口

  • 概念: 

1.接口是指定一组函数成员,而不实现他们的引用类型。
2.接口使用interface 关键字进行定义,可由方法、属性、事件、索引器或这四种成员类型的任意组合构成。

3.接口是一种规则。类似于电脑上的USB插口,如果电脑想使用U盘之类的,必须要遵守U盘的规则,需要在电脑上装上USB插口。 

  • 接口的特点: 

1、接口类似于抽象基类,不能直接实例化接口;接口中的方法都是抽象方法,实现接口的任何非抽象类型都必须实现接口的所有成员:
2、当显式实现该接口的成员时,实现的成员不能通过类实例访问,只能通过接口实例访问。
3、当隐式实现该接口的成员时,实现的成员可以通过类实例访问,也可以通过接口实例访问,但是实现的成员必须是公有的。
4、接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型、不能包含静态成员。
5、接口成员是默认public,且不能包含任何访问修饰符。
6、接口自身可从多个接口继承,类和结构可继承多个接口,但接口不能继承类。
7、当一个类既继承基类,又继承接口的时候,必须基类写在前面,基类和接口用逗号隔开,一个类只能有一个基类,可以继承许多接口。


    // 定义一个爬树接口
    public interface IClimbTree
    {
        void ClimbTree();
    }
    // 定义一个抓老鼠接口
    public interface ICatchMice
    {
        void CatchMice();
    } 
    // 定义一个宠物类
    public class Pet
    {
        public void Eat()
        {
            Console.WriteLine("吃着真香");
        }
    }

    // 猫猫类,继承于宠物类,又实现了爬树和抓老鼠接口
    public class Cat:Pet,IClimbTree,ICatchMice
    {

        public void ClimbTree()
        {
            Console.WriteLine("我会爬树");
        }

        public void CatchMice()
        {
            Console.WriteLine("我会抓老鼠");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            //实例化一个猫咪对象
            Cat cat = new Cat();
            cat.Eat();
            cat.ClimbTree();
            cat.CatchMice();
            Console.ReadLine();
        }
    }
  • 显示接口: 

 如果继承接口的类中的方法与接口的方法重名时,此时可以显示接口。

public interface IFlyable
{
    void Fly();
}

public void Bird:IFlyable
{
    public void Fly()
    {
        Console.WriteLine("鸟会飞");
    }
    //显示接口的方法
    void IFlyable.Fly()
    {
        Console.WriteLine("我是接口的飞");
    }
}

//主函数
IFlyable fly = new Bird();
fly.Fly();//这是接口的飞
Bird bird = new Bird();
bird.fly();//这是自己的飞

 

 

3.部分类 

当多个人共同完成一个项目时,这些人对同一个类都有补充的,但是普通的类不像是方法,是不能命名相同的名字 ,所以需要关键字partial来将这个类变成部分类。

public partial void Person
{
    private string _name;
}

public partail void Person
{
    private int age;
}

//这两个类里里面的字段和方法是可以共用的。

 4.密封类

当想让一个类不继承别的类时,就可以使用关键字sealed来使这个类变成密封类。虽说不能继承别的类,但是别的类可以继承它。

public sealed void Person
{
    
}

5.重写父类的ToString()的方法 

 C#的每一个类和结构都隐式继承自System.Object,而Object提供了ToString()虚方法,所以任何类的对象都有ToString()方法,该方法可以将对象转化为字符串类型(也可理解为:将数值或其它类型对象转换为字符串类型),该方法为虚方法,可以重写。

  • 当不重写时: 
namespace Test
{
	public class Person
	{
    	
	}
}

//Main函数
Person p= new Person ;
Console.WriteLine(p.ToString());//输出的是这个对象所在的命名空间。
  • 当对父类重写时: 
namespace Test
{
	public class Person
	{
    	public override string ToString()
    	{
        	return "Hello World";
    	}
	}
}
//Main函数
Person p= new Person ;
Console.WriteLine(p.ToString());//输出Hello World

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值