博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Python3 与 C# 面向对象之~继承与多态
阅读量:6850 次
发布时间:2019-06-26

本文共 12694 字,大约阅读时间需要 42 分钟。

 

2.继承

代码裤子:

在线编程:

在线预览:

2.1.单继承

在OOP中,当我们定义一个Class的时候,可以从某个现有的Class继承

新的Class称为子类,而被继承的class称为 基类 或者 父类

Python的继承格式 ==> xxx(base_class)

小明兴高采烈的听着老师开新课,不一会就看见了一个演示Demo:

In [1]:
class Animal(object):    def eat(self):        print("动物会吃")class Cat(Animal):    # 注意一下Python的继承格式    passclass Dog(Animal):    passdef main():    cat = Cat()    dog = Dog()    cat.eat()    dog.eat()if __name__ == "__main__":    main()
 
动物会吃动物会吃
 

当听到老师说:“私有的属性方法 不会被子类继承 ”的时候,小明心里一颤,联想到之前讲的 类属性实例属性实例方法类方法静态方法,于是赶紧写个Demo验证一下:

In [2]:
class Animal(object):    # 类属性    name = '动物'    def __init__(self):        # 实例属性        self.age = 1    def __bug(self):        """实例私有方法"""        print("我是动物类身上的私有方法:bug")    def eat(self):        """实例方法"""        print("我是实例方法,动物会吃哦~")    @classmethod    def call(cls):        """类方法"""        print("我是类方法,动物会叫哦")    @staticmethod    def play():        """静态方法"""        print("我是静态方法,动物会玩耍哦")class Dog(Animal):    passdef main():    dog = Dog()    # 实例属性    print(dog.age)    # 实例方法    dog.eat()    # 类属性    print(dog.name)    # 类方法    dog.call()    Dog.call()    Animal.call()    # 静态方法    dog.play()    Dog.play()    Animal.play()if __name__ == '__main__':    main()
 
1我是实例方法,动物会吃哦~动物我是类方法,动物会叫哦我是类方法,动物会叫哦我是类方法,动物会叫哦我是静态方法,动物会玩耍哦我是静态方法,动物会玩耍哦我是静态方法,动物会玩耍哦
 

来张图就懂了,不是 私有的 都能访问:

一张图就懂了

这时候,小明老高兴了,单回头一想 ==> 不科学啊,dog应该有其对应的方法吧,C#有虚方法重写,Python怎么搞?在子类里面又怎么调用父类方法呢?

对于小明的提示老师很高兴,于是点名小潘来写一个子类调用父类的demo(老师昨天从窗户里看见小潘有预习):

In [3]:
# 调用父类的方法class Father(object):    def eat(self):        print("文雅的吃饭")class Son(Father):    def eat(self):        # 调用父类方法第1种(super().方法)        super().eat()class GrandSon(Son):    def eat(self):        # 调用父类方法第2种(记得传self)        Son.eat(self)def main():    xiaoming = Son()    xiaoming.eat()    xiaoli = GrandSon()    xiaoli.eat()if __name__ == '__main__':    main()
 
文雅的吃饭文雅的吃饭
 

一般我们使用super().方法来调用父类方法

第二种方法类名.方法(self)千万别忘记传self哦

对了,C#是用base关键词,别搞混了

小明这时候可不高兴了,风头怎么能被小潘全部抢走呢,赶紧问问旁边同样预习的伟哥

不一会儿淡定的发了份重写父类方法的demo给老师:

In [4]:
# 重写父类方法==>子类和父类有同名方法class Father(object):    def __init__(self, name):        self.name = name    def eat(self):        print("%s喜欢文雅的吃饭" % self.name)class Son(Father):    def __init__(self, name):        super().__init__(name)    def eat(self):        print("%s喜欢大口吃饭大口喝酒" % self.name)def main():    xiaoming = Father("小明")    xiaoming.eat()    xiaopan = Son("小潘")    xiaopan.eat()if __name__ == "__main__":    main()
 
小明喜欢文雅的吃饭小潘喜欢大口吃饭大口喝酒
 

老师半喜半忧的说道:“小明同学啊,你也老大不小了,怎么跟孩子一样啊?案例不错,但是怎么能人身攻击人家小潘了?”

当子类和父类都存在相同的eat()方法时,我们说,子类的eat()覆盖了父类的eat()

在代码运行的时候,总是会调用子类的eat() 这样,我们就获得了继承的另一个好处:多态

2.2.多继承

在讲多态之前,我们先引入一下Python的 多继承 对,你没有听错

Java、C#都是单继承,多实现。Python和C++一样,可以多继承,先不要吐槽,规范使用其实很方便的

来个案例看看:

In [5]:
# 多继承引入class Father(object):    def eat(self):        print("文雅的吃饭")class Mom(object):    def run(self):        print("小碎步")class Son(Father, Mom):    passdef main():    son = Son()    son.eat()    son.run()if __name__ == '__main__':    main()
 
文雅的吃饭小碎步
 

继承可以把父类的所有功能都直接拿过来,这样就不必重0开始写代码,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写

注意一个情况,如果父类里面有同名方法咋办了?到底调哪个呢?

使用子类名.__mro__可以看在调方法的时候搜索顺序

一般同名方法都是 先看自己有没有,然后看继承顺序,比如这边 先看Mom再看Father

In [6]:
# 如果父类里面有同名方法怎么知道调哪个?class Father(object):    def eat(self):        print("文雅的吃饭")class Mom(object):    def eat(self):        print("开心的吃饭")class Son(Mom, Father):    passdef main():    son = Son()    son.eat()    print(Son.__mro__)  # 一般同名方法都是先看自己有没有,然后看继承顺序,比如这边先看Mom再看Fatherif __name__ == '__main__':    main()
 
开心的吃饭(
,
,
,
)
 

Python的多继承最好是当C#或者Java里面的接口使用,这样结构不会混乱(特殊情况除外)

来个例子:

class Animal(object):    passclass Flyable(object):    """飞的方法"""    passclass Runable(object):    """跑的方法"""    passclass Dog(Animal, Runable):    passclass Cat(Animal, Runable):    passclass Bird(Animal, Flyable):    passclass Dack(Animal, Runable, Flyable):    """鸭子会飞也会跑"""    pass

和C#一样,Python的 父类构造函数不会被继承

其实从资源角度也不应该被继承,如果有1w个子类,那每个子类里面都有一个父类方法,想想这是多么浪费的一件事情?


2.3.C#继承

下课后,小明认真思考总结,然后对照Python写下了C#版的继承:

定义一个人类

public class Person{
public string Name {
get; set; } public ushort Age {
get; set; } public Person(string name, ushort age) {
this.Name = name; this.Age = age; } public void Hi()//People {
Console.WriteLine("Name: " + this.Name + " Age: " + this.Age); } public virtual void Show()//People {
Console.WriteLine("Name: " + this.Name + " Age: " + this.Age); }}

定义一个学生类

public class Student : Person{
#region 属性 /// /// 学校 /// public string School {
get; set; } /// /// 班级 /// public string StrClass {
get; set; } /// /// 学号 /// public string StrNum {
get; set; } #endregion #region 构造函数 /// /// 调用父类构造函数 /// /// /// public Student(string name, ushort age) : base(name, age) {
} public Student(string name, ushort age, string school, string strClass, string strNum) : this(name, age) {
this.School = school; this.StrClass = strClass; this.StrNum = strNum; } #endregion /// /// new-隐藏 /// public new void Hi()//Student {
Console.WriteLine("Name: " + this.Name + " Age: " + this.Age + " School: " + this.School + " strClass: " + this.StrClass + " strNum: " + this.StrNum); } /// /// override-覆盖 /// public override void Show()//Student {
Console.WriteLine("Name: " + this.Name + " Age: " + this.Age + " School: " + this.School + " strClass: " + this.StrClass + " strNum: " + this.StrNum); }}

调用一下:

Person p = new Student("app", 10, "北京大学", "001", "01001");p.Hi(); p.Show();Console.WriteLine();Student s = p as Student;s.Hi(); s.Show();

结果:

Name: app Age: 10Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001Name: app Age: 10 School: 北京大学 strClass: 001 strNum: 01001

2.4C#接口的多实现

定义两个接口:

public interface IRun{
//什么都不用加 void Run();}public interface IEat{
void Eat();}

定义一个Dog类来实现两个接口,这样dog就有了run和eat的方法了

var dog = new Dog();dog.Eat();dog.Run();

结果:

狗狗吃狗狗跑

3 多态

3.1.Python

说多态之前说说类型判断,以前我们用type() or isinstance()

判断一个变量和另一个变量是否是同一个类型==> type(a)==type(b)

判断一个变量是否是某个类型==> type(a)==A or isinstance(a,A)

In [7]:
# 判断一个变量是否是某个类型 ==> isinstance() or typeclass Animal(object):    passclass Dog(Animal):    passdef main():    dog = Dog()    dog2 = Dog()    print(type(dog) == Dog)    print(type(dog) == type(dog2))    print(type(dog))    print(isinstance(dog, Dog))    print(isinstance(dog, Animal))    # arg 2 must be a type or tuple    # print(isinstance(dog, dog2))if __name__ == '__main__':    main()
 
TrueTrue
TrueTrue
 

小明老高兴了,终于讲解多态了,不禁问道:“多态的好处是啥?”

小潘瞥了一眼小明~“废话,肯定为了 屏蔽子类差异用的啊,像简单工厂不就干的这个事?"

小明楞了楞,眼巴巴的看着老师继续讲课。

设计模式我们会找个专题讲讲,现在给你们说的是Python的基础。

Python是动态语言的“鸭子类型”,它并不要求严格的继承体系。

一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子(最后会贴一个案例)

C#实现多态有很多方式,比如虚方法,比如抽象类,比如接口等等...

小明迷迷糊糊的问道:“那 Python怎么实现多态呢?”

老师看了一眼打断他讲课的小明,然后继续说道~来个简单案例:

In [8]:
class People(object):    def eat(self):        print("人类会吃饭")class Father(People):    def eat(self):        print("优雅的吃饭")class Teacher(People):    def eat(self):        print("赶时间的吃饭")# C# 或者 Java里面 写成 eat(People obj)def eat(obj):    obj.eat()def main():    teacher = Teacher()    father = Father()    eat(teacher)    eat(father)if __name__ == '__main__':    main()
 
赶时间的吃饭优雅的吃饭
 

多态的好处在于,如果这时候我再来个Son子类,只要eat()方法编写正确,不用管原来的代码是如何调用的

这次小明懂了,为了装一下,说道:”老师老师,我记得C# 或者 Java里面是写成 eat(People obj) 的吧?“

老师欣慰的笑了一下,说道:”记得刚才说的填鸭式吗?Python这么写有个好处哦,我们来看个案例,然后你自己总结“

In [9]:
class People(object):    def eat(self):        print("人类会吃饭")class Father(People):    def eat(self):        print("优雅的吃饭")class Teacher(People):    def eat(self):        print("赶时间的吃饭")class Dog(object):    def eat(self):        print("舔着吃")def eat(obj):    obj.eat()def main():    teacher = Teacher()    father = Father()    eat(teacher)    eat(father)        # 我们添加一个不是People子类的Dog类,只要有eat方法,参数一样就可以直接调    dog = Dog()    eat(dog)if __name__ == '__main__':    main()
 
赶时间的吃饭优雅的吃饭舔着吃
 

小明赶紧结合之前学的内容写了个小案例:

In [10]:
class People(object):    def eat(self):        print("人类会吃饭")class Father(People):    def eat(self):        print("优雅的吃饭")class Dog(object):    def eat(self):        print("舔着吃饭")class Factory(object):    @classmethod    def eat(cls, obj):        if hasattr(obj, "eat"):            obj.eat()        else:            raise Exception("该类没有eat()方法!")def main():    people = People()    father = Father()    dog = Dog()        Factory.eat(people)    Factory.eat(father)    Factory.eat(dog)if __name__ == '__main__':    main()
 
人类会吃饭优雅的吃饭舔着吃饭
 

小明突然大声说道:”老师老师,我知道了,Python这是吧类的继承和接口继承融合起来了啊,实现多态就相当于C#里面的接口实现多态啊!!!“

老师点评道:”你姑且可以这么理解,这些我们后面还会继续说的,这种填鸭式的手段刚开始的确会有点不方便,用着用着你就会觉得挺方便的“


小明认真思考总结,然后对照Python和小潘一起写下了 C#版的多态

3.2.C#虚方法实现多态

定义一个人类:

public class Person{
#region 字段+属性 /// /// 姓名 /// private string _name; public string Name {
get {
return _name; } set {
_name = value; } } /// /// 性别 /// private bool _gender; public bool Gender {
get {
return _gender; } set {
_gender = value; } } /// /// 年龄 /// public short Age {
get; set; } #endregion #region 构造函数 public Person() {
} public Person(string name, bool gender) {
this.Name = name; this.Gender = gender; } public Person(string name, bool gender, short age) : this(name, gender) {
this.Age = age; } #endregion #region 方法 /// /// 打招呼 /// public virtual void SaiHi() {
Console.WriteLine("我是一个人类!"); } #endregion}

定义一个女孩类:

public class Gril : Person{
#region 构造函数 public Gril() {
} public Gril(string name, bool gender) : base(name, gender) {
} public Gril(string name, bool gender, short age) : base(name, gender, age) {
} #endregion /// /// 重写父类方法 /// public override void SaiHi() {
string genderStr = Gender == true ? "男孩" : "女孩"; Console.WriteLine($"你好,我叫{Name},今年{Age}岁了,我是一个腼腆的小{genderStr}"); }}

定义一个男孩类:

public class Boy : Person{
#region 构造函数 public Boy() {
} public Boy(string name, bool gender) : base(name, gender) {
} public Boy(string name, bool gender, short age) : base(name, gender, age) {
} #endregion //public void SaiHi() public override void SaiHi() {
string genderStr = Gender == true ? "男孩" : "女孩"; Console.WriteLine($"你好,我叫{Name},今年{Age}岁了,我是一个腼腆的小{genderStr}"); }}

调用:

static void Main(string[] args){
Person[] persons = {
new Person(), new Boy("铁锅", true, 13), new Gril("妞妞", false, 22) }; foreach (var item in persons) {
//看看item里面到底放的是什么 Console.WriteLine(item.ToString()); item.SaiHi(); Console.WriteLine(); }}

结果:

Polymorphism1.Person我是一个人类!Polymorphism1.Boy你好,我叫铁锅,今年13岁了,我是一个腼腆的小男孩Polymorphism1.Gril你好,我叫妞妞,今年22岁了,我是一个腼腆的小女孩
 

3.3.C#抽象类实现多态

定义一个动物类:

public abstract class Animal{
/// /// 抽象类中可以有正常的方法 /// public void Action() {
Console.WriteLine("动物可以动"); } /// /// 抽象方法必须在抽象类中 /// public abstract void Call();}

定义一个猫科动物类(子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类)

/// /// 猫科动物---子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类/// public abstract class Feline : Animal{
}

定义一个猫类

public class Cat : Feline{
/// /// 子类必须实现父类抽象方法,如果不实现,那么该类也必须是抽象类 /// public override void Call() {
Console.WriteLine("喵喵叫~~~"); }}

定义一个狗类

public class Dog : Animal{
/// /// 子类必须实现抽象类中的抽象方法 /// public override void Call() {
Console.WriteLine("汪汪叫~~~"); }}

调用:

Animal[] animals = {
new Dog(), new Cat() };foreach (var item in animals){
item.Call();}

结果:

汪汪叫~~~喵喵叫~~~
 

3.4.C#接口实现多态

定义一个跑的接口:

public interface IRun{
/// /// 接口中可以声明属性,方法,索引器等 /// //string Name { get; set; } void Runing();}

定义一个猫类:

public class Cat : IRun{
public void Runing() {
Console.WriteLine("飞快的跑着上树"); }}

定义一个学生类:

public class Student : IRun{
public void Runing() {
Console.WriteLine("飞快的跑着去上课"); }}

调用:

IRun[] objs = {
new Student(), new Cat() };foreach (var item in objs){
item.Runing();}

结果:

飞快的跑着去上课飞快的跑着上树

转载于:https://www.cnblogs.com/dunitian/p/9220364.html

你可能感兴趣的文章
sql server的两个类型转换函数
查看>>
js定时器setInterval()与setTimeout()
查看>>
python基础===修改idle的输入风格
查看>>
Jmeter===参数化
查看>>
Webview访问移动网络的两种方法
查看>>
GIT与SVN的区别
查看>>
scala模式匹配详细解析
查看>>
CSS动画之过渡模块
查看>>
斯特林数
查看>>
css-实现元素垂直居中对齐
查看>>
mysql添加外键语句
查看>>
Objective-C语法之动态类型(isKindOfClass, isMemberOfClass,id)等
查看>>
Django框架----路由系统、视图和模板(简单介绍)
查看>>
MySQL 添加审计功能
查看>>
动手动脑及课后实验整理集合
查看>>
初识webpack——webpack四个基础概念
查看>>
Bootstrap下拉菜单
查看>>
poj2250
查看>>
初识Hadoop
查看>>
动态规划
查看>>