📜  R——面向对象编程

📅  最后修改于: 2022-05-13 01:55:25.429000             🧑  作者: Mango

R——面向对象编程

在本文中,我们将讨论 R 编程语言中的面向对象编程 (OOP)。我们将讨论 S3 和 S4 类、这些类中的继承以及这些类提供的方法。

在 R 编程中,OOP 提供类和对象作为降低和管理程序复杂性的关键工具。 R 是一种使用 OOP 概念的函数式语言。我们可以把一个类想象成一辆汽车的草图。它包含有关 model_name、model_no、engine 等的所有详细信息。根据这些描述,我们选择一辆车。汽车是对象。每个汽车对象都有自己的特点和特点。对象也称为类的实例,创建此对象的过程称为实例化。在 R 中,S3 和 S4 类是面向对象编程的两个最重要的类。但在讨论这些类之前,让我们先简要介绍一下类和对象。

类和对象

类是通过封装数据成员和函数来制作对象的蓝图或原型。对象是一种数据结构,其中包含一些作用于其属性的方法。

班级学生的对象

S3 级

S3 类没有预定义的定义并且能够调度。在这个类中,泛型函数调用该方法。 S3 的简单实现是可能的,因为它不同于实现面向对象消息传递的传统编程语言Java、C++ 和 C#。

创建 S3 类

要创建此类的对象,我们将创建一个包含所有类成员的列表。然后这个列表作为参数传递给 class() 方法。

句法:

例子:

在下面的代码中,定义了一个 Student 类。给出具有属性学生姓名和卷号的适当班级名称。然后创建并调用学生类的对象。

R
# List creation with its attributes name
# and roll no.
a < - list(name="Adam", Roll_No=15)
 
# Defining a class "Student"
class(a) < - "Student"
 
# Creation of object
a


R
methods(print)


R
# List creation with its attributes name
# and roll no.
a = list(name="Adam", Roll_No=15)
 
# Defining a class "Student"
class(a) = "Student"
 
# Creation of object
print(a)


R
print.Student <- function(obj){
  cat("name: " ,obj$name, "\n")
  cat("Roll No: ", obj$Roll_No, "\n")
}
 
print(a)


R
attributes(a)


R
attr(a, "age")<-c(18)
attributes(a)


R
# student function with argument
# name(n) and roll_no(r)
student < - function(n, r) {
    value < - list(name=n, Roll=r)
    attr(value, "class") < - "student"
    value
}


R
# 'print.student' method created
print.student < - function(obj) {
 
    # 'cat' function is used to concatenate
    # strings
    cat("Name:", obj$name, "\n")
    cat("Roll", obj$roll, "\n")}


R
s < - list(name="Kesha", Roll=21, country="India")
 
# child class 'Student' inherits
# parent class 'student'
class(s) < - c("Student", "student")
s


R
# 'Student' class object is passed
# in the function of class 'student'
 
print.student < - function(obj) {
    cat(obj$name, "is from", obj$country, "\n")
}
s


R
# Function setClass() command used
# to create S4 class containing list of slots.
setClass("Student", slots=list(name="character",
                               Roll_No="numeric"))
 
# 'new' keyword used to create object of
# class 'Student'
a <- new("Student", name="Adam", Roll_No=20)
 
# Calling object
a


R
stud <- setClass("Student", slots=list(name="character",
                               Roll_No="numeric"))
 
# Calling object
stud


R
stud(name="Adam", Roll_No=15)


R
# Define S4 class
setClass("student",
         slots=list(name="character",
                    age="numeric", rno="numeric")
         )
 
# Defining a function to display object details
setMethod("show", "student",
          function(obj){
              cat(obj@name, "\n")
              cat(obj@age, "\n")
              cat(obj@rno, "\n")
          }
          )
 
# Inherit from student
setClass("InternationalStudent",
         slots=list(country="character"),
         contains="student"
         )
 
# Rest of the attributes will be inherited from student
s < - new("InternationalStudent", name="Adam",
          age=22, rno=15, country="India")
show(s)


输出:

$name
[1] "Adam"

$Roll_No
[1] 15

attr(, "class")
[1] "Student"

通用函数

泛型函数是多态性的一个很好的例子。要理解泛型函数的概念,请考虑 print()函数。 print()函数是为 R 编程语言中的不同数据类型和数据结构创建的各种打印函数的集合。它根据作为参数传递的对象类型调用适当的函数。我们可以使用 methods()函数查看打印函数的各种实现。

示例:查看不同类型的打印函数

R

methods(print)

输出:

r 泛型函数

现在让我们创建一个我们自己的通用函数。我们将为我们的类创建打印函数,它将以我们指定的格式打印所有成员。但在创建打印函数之前,让我们先创建打印函数对我们的类所做的事情。

例子:

R

# List creation with its attributes name
# and roll no.
a = list(name="Adam", Roll_No=15)
 
# Defining a class "Student"
class(a) = "Student"
 
# Creation of object
print(a)

输出:

$name
[1] "Adam"

$Roll_No
[1] 15

attr(,"class")
[1] "Student"

现在让我们以我们指定的格式打印所有成员。考虑下面的例子——

例子:

R

print.Student <- function(obj){
  cat("name: " ,obj$name, "\n")
  cat("Roll No: ", obj$Roll_No, "\n")
}
 
print(a)

输出:

name:  Adam 
Roll No:  15 

属性

对象的属性不影响对象的值,但它们是用于处理对象的一条额外信息。函数attributes() 可用于查看对象的属性。

示例:创建 S3 对象并显示其属性。

R

attributes(a)

输出:

$names
'name''Roll_No'
$class
'Student'

此外,您可以使用 attr 向对象添加属性。

R

attr(a, "age")<-c(18)
attributes(a)

输出:

$names
'name''Roll_No'
$class
'Student'
$age
18

S3 类中的继承

继承是OOP(面向对象编程)中的一个重要概念,它允许一个类派生另一个类的特性和功能。此功能有助于代码的可重用性。

R 编程语言中的 S3 类没有正式和固定的定义。在 S3 对象中,具有其类属性的列表设置为类名。 S3 类对象仅从其基类继承方法。

例子:

在下面的代码中,继承是使用 S3 类完成的,首先创建的对象是类 student。

R

# student function with argument
# name(n) and roll_no(r)
student < - function(n, r) {
    value < - list(name=n, Roll=r)
    attr(value, "class") < - "student"
    value
}

然后,定义该方法以打印学生的详细信息。

R

# 'print.student' method created
print.student < - function(obj) {
 
    # 'cat' function is used to concatenate
    # strings
    cat("Name:", obj$name, "\n")
    cat("Roll", obj$roll, "\n")}

现在,通过执行class(obj) <- c(child, parent)创建另一个类时完成继承。

R

s < - list(name="Kesha", Roll=21, country="India")
 
# child class 'Student' inherits
# parent class 'student'
class(s) < - c("Student", "student")
s

输出:

Name: Kesha 
Roll: 21 

以下代码覆盖了班级学生的方法。

R

# 'Student' class object is passed
# in the function of class 'student'
 
print.student < - function(obj) {
    cat(obj$name, "is from", obj$country, "\n")
}
s

输出:

Kesha is from India

S4班

S4 类有一个预定义的定义。它包含用于定义方法和泛型的函数。它使多次调度变得容易。此类包含用于定义方法和泛型的辅助函数。

创建 S4 类和对象

setClass()命令用于创建 S4 类。以下是 setclass 命令的语法,它表示带有包含名称和 rollno 的插槽的 myclass。

句法:

new()函数用于创建 S4 类的对象。在这个函数中,我们将传递类名以及插槽的值。

例子:

R

# Function setClass() command used
# to create S4 class containing list of slots.
setClass("Student", slots=list(name="character",
                               Roll_No="numeric"))
 
# 'new' keyword used to create object of
# class 'Student'
a <- new("Student", name="Adam", Roll_No=20)
 
# Calling object
a

输出:

Slot "name":
[1] "Adam"

Slot "Roll_No":
[1] 20

从生成器函数创建 S4 对象

setClass() 返回一个生成器函数,它有助于创建对象,它充当构造函数。

例子:

R

stud <- setClass("Student", slots=list(name="character",
                               Roll_No="numeric"))
 
# Calling object
stud

输出:

现在上面创建的 stud函数将充当 Student 类的构造函数。它将表现为 new()函数。

例子:

R

stud(name="Adam", Roll_No=15)

输出:

An object of class "Student"
Slot "name":
[1] "Adam"

Slot "Roll_No":
[1] 15

S4类中的继承

R 编程中的 S4 类具有适当的定义,派生类将能够从其基类继承属性和方法。为此,我们将首先创建一个具有适当插槽的基类,并为该类创建一个通用函数。然后我们将创建一个派生类,该派生类将使用 contains 参数进行继承。派生类将继承基类的成员和函数。

例子:

R

# Define S4 class
setClass("student",
         slots=list(name="character",
                    age="numeric", rno="numeric")
         )
 
# Defining a function to display object details
setMethod("show", "student",
          function(obj){
              cat(obj@name, "\n")
              cat(obj@age, "\n")
              cat(obj@rno, "\n")
          }
          )
 
# Inherit from student
setClass("InternationalStudent",
         slots=list(country="character"),
         contains="student"
         )
 
# Rest of the attributes will be inherited from student
s < - new("InternationalStudent", name="Adam",
          age=22, rno=15, country="India")
show(s)

输出:

Adam 
22 
15

同时定义 S3 和 S4 类的原因如下:

  • 如果直接调用 S3 泛型函数,则不会单独看到 S4 类。例如,如果某个函数从一个包中调用unique() ,而该包没有使该函数成为 S4 泛型,就会出现这种情况。
  • 但是,原始函数和运算符是例外:当且仅当对象是 S4 对象时,内部 C 代码才会查找 S4 方法。 S4 方法分派将用于分派任何一个操作数是 S4 对象的二元运算符调用。
  • 如果有任何符合条件的非默认 S4 方法,则不会单独调用 S3 类。

因此,如果一个包为 S4 类定义了唯一的 S3 方法,但另一个包为该类的超类定义了 S4 方法,则将选择超类方法,可能不是预期的。