R语言面向对象基础

第四章 类和对象

S3 类S4类引用类
缺乏形式定义使用setClass()定义使用setRefClass()定义类
通过设置类的属性来创建对象使用new()创建对象使用构造函数创建对象
使用$访问属性使用@访问属性使用$访问属性
方法属于泛型函数方法属于泛型函数方法属于类
遵守修改时拷贝的语义遵守修改时拷贝的语义不遵守修改时拷贝的语义
  • 遵守修改时拷贝:
    • 也称为写时拷贝,或深拷贝,或值传递。
    • 即声明类对象a,b 令 b <- a。则a,b对象存储数据内容相同,但指针地址不相同,修改对象属性元素互不影响。
  • 不遵守修改时拷贝:
    • 也称为浅拷贝,或引用传递。
    • 即即声明类对象a,b 令 b <- a。则a,b对象存储相同指针地址,指向相同数据,一方修改对象属性内容时另一方也收到影响。

1. S3类

  • 出自于第三代S语言,核心思想是使用list来构建对象,再给对象添加class属性或强制修改对象的class内容

  • 创建S3类对象

    • 方法一:
    # list ---> class
    s <- list(name = "Han meimei", age = 20, GPA = 3.8)
    class(s)
    class(s) <- "student"
    class(s)
    
    • 方法二:
    s1 <- list(name = "Li lei", age = 22, GPA = 3.7)
    attr(s1, "class") <- "student"
    class(s1)
    
    • 方法三:
    student1 <- function(name, id, age) {
      s_obj <- list(s_name = name,
                    s_id = id,
                    s_age = age)
      attr(s_obj, "class") <- "student1"
      return(s_obj)
    }
    # 生成对象实例
    s2 <- student1("Alice", 2020001, 21)
    s2
    
    #访问s2对象的属性值
    s2$name
    
  • S3类的泛型函数

    • 系统定义的泛型函数无需声明其泛型特性,即不需要UseMethod来指明其是泛型。
    • 自定义泛型函数需要先进行UseMthod的声明。
    #控制台直接输出print,可查看到print的泛型声明
    #控制台直接输出plot,可查看到plot的泛型声明
    
    #print函数的泛型,针对student1类的处理,直接打印
    print.student1 <- function(student) {
      cat("This is a generic function for print student")
    }
    
    #自定义泛型函数bornyear的声明
    bornyear <- function(para) {
      UseMethod("by")
    }
    
    #bornyear针对student1类的处理
    bornyear.student1 <- function(student) {
      byear <- 2020 - student$s.age
      cat("Your name:", student$s.name, "Your born year:", byear)
    }
    
    #bornyear针对student类的处理
    bornyear.student <- function(student) {
      cat("Your name:", student$name, "Your GPA:", student$GPA)
    }
    
    #bornyear针对其他不属于student1和student类的处理
    bornyear.default <- function() {
      cat("This is a default method")
    }
    

2. S4类

  • 核心思想是使用setClass函数来创建S4类的定义,通过参数指明类名称,通过参数slot传入一个列表来指明类属性以及其数据类型。最后通过new函数来生成S4类的实例。
# 定义
setClass("student_s4",
         slots = list(name = "character", age = "numeric", GPA = "numeric"))

# 对象的生成
s <- new("student_s4") # 属性值为空的对象
#生成带属性值的对象
s <- new("student_s4",
         name = "Xin kuzi",
         age = 21L,
         GPA = 3.8)
  • 本质上setClass函数返回的是一个构造函数,因此可以使用一个变量名来接收setClass的返回结果,因此之后使用此变量名对象作为构造函数来生成对象。
  • 方法二创建S4类和其对象。
#创建构造函数
student_s4_generator <- setClass("student_s4",
                                 slots = list(name = "character", age = "numeric", GPA = "numeric"))
#使用构造函数生成对象
s1 <- student_s4_generator(name = "Peng Lei", age = 21,  GPA = 3.9)

  • 访问属性值时使用@符号
s1@name
s1@age
  • 泛型函数的使用

    • 对于系统泛型,可以使用setMethod直接定义,如show方法
    • 对于自定义泛型,需要用setGeneric声明,且可以选择在其中将默认default的情况定义好。
    #show函数是S4类的泛型函数,由系统定义,因此无需声明其泛型特点
    
    setMethod ("show", “student",function (object) {
        cat (object@name, "\n")
        cat ("Age:", object@age, "years old\n")
        cat ("GPA:", object@GPA, "\n")
    })
    
    #S4 自定义泛型函数
    #对于S4泛型函数的一般声明
    
    setGeneric("test", function(s4.obj)
      standardGeneric("test"))
               
    #对于S4泛型函数声明时处理其默认情况的状态
    setGeneric("test",function(s4.obj){
      print("this is generic function for default")
    })
               
    #对泛型函数进行处理,指明泛型函数的名称,signature指明当前处理的类型,function用来设计
    #泛型的具体方法。
    setMethod("test", signature = "student_s4", function(s4.obj) {
      print("This is a test method for s4 class")
      cat("S4 object: \n", "name: ", s4.obj@name, ", age= ", s4.obj@age)
    })
    
    test(s)
    test(s1)
    

3. 引用类

  • 核心思想是使用setRefClass来声明引用类的构造函数,指明类名,通过field参数传入一个列表来指明类的属性,通过methods参数传入一个列表来指明类的方法。
  • 因此引用类的方法是是属于引用类本身的。而S3,S4类的方法都是泛型方法,是脱离了类体定义的。
  • 生成引用类对象时直接用setRefClass返回的构造函数来生成即可。
# 类的创建,属性,方法
student_rc_generator <- setRefClass(
  "student_rc",
  fields = list(name = "character", age = "numeric", GPA = "numeric"),
  methods = list(
    s_rc_func = function(obj) {
      cat("Name: ", obj$name, ", Age: ", obj$age, ", GPA: ", obj$GPA)
    }
  )
)

#用构造函数生成对象
s_rc <- student_rc_generator(name = "Ciwei", age = 28, GPA = 3.5)
#查看对象类型以及内容
getClass(s_rc)
  • 测试引用类的浅拷贝
s_rc_cp <- s_rc #定义cp变量,完全拷贝s_rc对象
s_rc_cp$name <- "Pan ni xi lin"  #将cp的name改为其他值
s_rc_cp$name
s_rc$name  # 原始rc对象的name受影响


s_rc_cp <- s_rc$copy()  #调用copy函数,变为深拷贝,完成备份
s_rc_cp$name <- "Ciwei" #更改一方属性值
s_rc_cp$name
s_rc$name   #另一方不受影响

4. 继承关系

  • S3JI继承
student_s3 <- function(Pname, Page, PGPA) {
  s.obj <- list(name = Pname,
                GPA = PGPA,
                age = Page)
  attr(s.obj, "class") <- "student_s3"
  return(s.obj)
}

print.student_s3 <- function(s3_obj) {
  cat("This is a method for parent class")
}


s3_son <-
  list(
    name = "guowei VC",
    age = 21,
    GPA = 3.3,
    country = "China"
  )
class(s3_son) <- c("Inter_student_s3", "student_s3")

print(s3_son)

print.Inter_student_s3 <- function(s3_son_obj) {
  cat("This is a sub-class method")
}

inherits(s3_son, "student_s3")
is(s3_son, "student_s3")
is(s3_son, "Inter_student_s3")


  • S4继承
setClass("student_s4",
         slots = list(name = "character", age = "numeric", GPA = "numeric"))

setClass("Inter_student_s4",
         slots = list(country = "character"),
         contains = "student_s4")
s4_son <-
  new(
    "Inter_student_s4",
    name = "Jazz",
    age = 21,
    GPA = 3.3,
    country = "China"
  )
show(s4_son)

test(s4_son)
  • 引用类继承
inter_student_rc_generator <-
  setRefClass(
    "inter_student_rc",
    fields = list(country = "character"),
    contains = "student_rc",
    methods = list(
      rc_son_func = function() {
        "Just a test for sub-class method"
      },
      s_rc_func = function() {
        "rewrite the method of parent class"
      }
    )
  )

son_rc <-
  inter_student_rc_generator(
    name = "weipeng guo",
    age = 30,
    GPA = 0,
    country = "China"
  )

son_rc$s_rc_func()
son_rc$rc_son_func()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
>