zoukankan      html  css  js  c++  java
  • 类的继承实例

    类的继承实例

    继承

    面向对象编程 (OOP) 语言的一个主要功能就是“继承”。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。

    通过继承创建的新类称为“子类”或“派生类”。

    被继承的类称为“基类”、“父类”或“超类”。

    继承的过程,就是从一般到特殊的过程。

    要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。

    在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。

    继承概念的实现方式主要有2类:实现继承、接口继承。

    Ø         实现继承是指使用基类的属性和方法而无需额外编码的能力;
    Ø         接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力(子类重构爹类方法);
    在考虑使用继承时,有一点需要注意,那就是两个类之间的关系应该是“属于”关系。例如,Employee 是一个人,Manager 也是一个人,因此这两个类都可以继承 Person 类。但是 Leg 类却不能继承 Person 类,因为腿并不是一个人。
     
    抽象类仅定义将由子类创建的一般属性和方法。

    OO开发范式大致为:划分对象→抽象类→将类组织成为层次化结构(继承和合成) →用类与实例进行设计和实现几个阶段。

    下面我们来看个继承的简单实例:

    如果子类有一个跟父类一样的方法:

    我们现在给父类增加两个参数,name,age。

    这个时候调用子类用方法b=BlackPerson(),必须带上参数name和age,否则就会报错。如下图:

    子类调用必须加上参数如下图:

    如果我想给子类传参数,不可以在子类下面增加初始化函数。

    我们应该先继承再重构函数:

    甚至在子类里可以自定义新的属性了,如下图:

     现在我们来看一个完整的学校,老师和学生的例子:

    class SchoolMember(object):
        '''学校成员基类'''
        member = 0
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
            self.enroll()
        def enroll(self):
            '''注册'''
            print("just enrolled a new school member [%s]"% self.name)
            SchoolMember.member +=1
    
        def tell(self):
            print("------info:%s-----"%self.name)
            for k,v in self.__dict__.items():
                print("	",k,v)
    
            print("------end-----")
    
    
        def __del__(self):
            print("开除了[%s]..."% self.name )
            SchoolMember.member -=1
    
    class School(object):
         '''学校类'''
         def open_branch(self,addr):
             print("openning a new branch in ",addr)
    
    
    class Teacher(SchoolMember,School):
        '''讲师类'''
        def __init__(self,name,age,sex,salary,course):
            #SchoolMember.__init__(self,name,age,sex) #经典类写法
            super(Teacher,self).__init__(name,age,sex) #新式类写法
            self.salary = salary
            self.course = course
        # def tell(self):
        #     print("""--------info:%s
        #         name:%s
        #         age:%s
        #         salary :%s
        #     """ % (self.name,self.name,self.age,self.salary))
        def teaching(self):
            print("Teacher [%s] is teaching [%s]" % (self.name,self.course))
    
    class Student(SchoolMember):
        def __init__(self,name,age,sex,course,tuition):
            SchoolMember.__init__(self,name,age,sex)
            self.course = course
            self.tuition = tuition #fee
            self.amount = 0
        def pay_tuition(self,amount):
            print("student [%s] has just paied [%s]" %(self.name,amount))
            self.amount += amount
    
    t1 = Teacher("Wusir", 28, "F*M",3000,"Python" )
    s1 = Student("HaiTao", 38,"N/A","PYS15", 300000 )
    s2 = Student("LIChuang",12,"M","PYS15", 11000 )
    
    print(SchoolMember.member)
    t1.tell()
    t1.open_branch("SH")
    s2.tell()
    del s2
    
    print(SchoolMember.member)

    上面的例子,几个注意要点:

    这必须用类名SchoolMember而不能用self,如果用self就没法实现全局变量进行累加的效果了~!

    我们如果想打印老师和学生,实例的所有信息,怎么便捷的操作呢?

    我们发现实例后面.__dict__可以用字典的方式把所有的信息打印出来:

    那么我们可以在父类直接加上循环打印实例信息。

    在上面代码里,还有一个多继承的问题,也就是老师其实继承了2个父类,一个SchoolMember一个是School。

    最后我们来看下继承父类有两个写法,新式类VS经典类:

    其实新式类的定义class Person(object),这个object也是一个系统默认的类,那么为什么python要让所有的类的父类都是object呢?

    因为万一以后python想给类class加什么新功能,它直接加在class object的方法就可以,这样就可以无限扩展了!所以推荐用新式类的写法来给类定义。

    现在我们再来看一个在经典模式和新式模式下,构建函数,初始化的查找顺序问题:

    在默认的情况下,见下面的代码:

    class A(object):
        def __init__(self):
            self.n = "A"
    class B(A):
        # pass
        def __init__(self):
            self.n = "B"
    class C(A):
        #pass
        def __init__(self):
            self.n = "C"
    class D(B,C):
        # pass
        def __init__(self):
            self.n = "D"
    d = D()
    print(d.n)

    打印出来的结果肯定是D,这个时候搜索的最近的初始化。

    如果我们把D的初始化注释掉:

    这个时候打印出来的结果是B;

    同样我们把B注释掉,打印出来的是C;

    再把C注释掉,打印出来的是A。

    我们来看下面的关系图:

    查找的顺序是D->B->C->A,也就是在PY3里,查找的顺序是按广度查询的方式,先在同级的class查找,然后再按深度查询的方法,查找到A。

    同样在经典模式的情况下,也就是把A的object去掉:

    这个时候在PY3里查找的顺序依旧是D->B->C->A。

    但是注意,有特殊的情况,如果在PY2里,经典模式的查找顺序就是D->B->A->C,在PY2里查找的顺序优先是深度查找,然后才是广度查询!

  • 相关阅读:
    linux2.6.37内核接两个硬盘导致读写效率变低的问题
    使用kprobes查看内核内部信息
    linux下内存大小、起始地址的解析与修改
    docker fastadmin
    JAVAEE——BOS物流项目11:在realm中授权、shiro的方法注解权限控制、shiro的标签权限控制、总结shiro的权限控制方式、权限管理
    mysql 错误解决:Plugin 'FEDERATED' is disabled. /usr/sbin/mysqld: Table 'mysql.plugin' doesn't exist
    JAVAEE——BOS物流项目10:权限概述、常见的权限控制方式、apache shiro框架简介、基于shiro框架进行认证操作
    错误解决:HibernateSystemException-HHH000142: Javassist Enhancement failed
    JAVAEE——BOS物流项目09:业务受理需求分析、创建表、实现自动分单、数据表格编辑功能使用方法和工作单快速录入
    JAVAEE——BOS物流项目08:配置代理对象远程调用crm服务、查看定区中包含的分区、查看定区关联的客户
  • 原文地址:https://www.cnblogs.com/itfat/p/7545173.html
Copyright © 2011-2022 走看看