R语言 面向对象的编程
在这篇文章中,我们将讨论R编程语言中的面向对象编程(OOPs)。我们将讨论S3和S4类,这些类的继承性,以及这些类提供的方法。
在R编程中,OOPs提供类和对象作为其关键工具,以减少和管理程序的复杂性。R是一种使用OOPs概念的功能语言。我们可以把一个类看作是一辆汽车的草图。它包含了所有关于车型名称、车型编号、发动机等的细节。基于这些描述,我们选择一辆汽车。汽车是一个对象。每个汽车对象都有自己的特点和特征。一个对象也被称为一个类的实例,创建这个对象的过程被称为实例化。在R语言中,S3和S4类是面向对象编程的两个最重要的类。但在讨论这些类之前,让我们先看看关于类和对象的简介。
类和对象
类是一个蓝图或原型,通过封装数据成员和函数,对象是由它构成的。一个对象是一个数据结构,它包含一些作用于其属性的方法。
S3类
S3类没有预定义的定义,能够进行调度。在这个类中,通用函数对方法进行了调用。轻松实现S3是可能的,因为它不同于传统的编程语言Java、C++和C#,后者实现了面向对象的消息传递。
创建S3类
为了创建这个类的一个对象,我们将创建一个包含所有类成员的列表。然后将这个列表作为参数传递给class()方法。
语法
variable_name <- list(attribute1, attribute2, attribute3....attributeN)
例子
在下面的代码中,定义了一个学生类。给出了一个适当的类名,其属性是学生的姓名和学号。然后,学生类的对象被创建和调用。
输出
泛型函数
通用函数是多态性的一个好例子。为了理解通用函数的概念,请考虑print()函数。print()函数是各种打印函数的集合,这些函数是为R编程语言中不同的数据类型和数据结构创建的。它根据作为参数传递的对象的类型,调用适当的函数。我们可以通过methods()函数看到打印函数的各种实现。
例子: 看到不同类型的打印函数
输出
现在让我们创建一个属于我们自己的通用函数。我们将为我们的类创建打印函数,它将以我们指定的格式打印所有的成员。但在创建打印函数之前,让我们先创建打印函数对我们类的作用。
例子
输出
现在让我们以我们指定的格式打印所有的成员。考虑一下下面的例子 –
例子
输出
属性
对象的属性不影响对象的值,但它们是用于处理对象的额外信息。函数attributes()可以用来查看一个对象的属性。
例子: 一个S3对象被创建,其属性被显示。
输出
另外,你可以通过使用attr来给一个对象添加属性。
输出
S3类中的继承性
继承是OOP(面向对象编程)的一个重要概念,它允许一个类派生出另一个类的特征和功能。这个特点有利于代码的重复使用。
R编程语言中的S3类没有正式和固定的定义。在一个S3对象中,一个带有其类属性的列表被设置为一个类名。S3类对象只继承其基类的方法。
例子
在下面的代码中,使用S3类进行了继承,首先创建了学生类的对象。
然后,该方法被定义为打印学生的详细信息。
现在,在创建另一个类时,通过做**class(obj) <- c(child, parent) **来完成继承。
输出
下面的代码覆盖了类student的方法。
输出
S4类
S4类有一个预定义的定义。它包含了定义方法和泛型的功能。它使多次派发变得容易。这个类包含用于定义方法和泛型的辅助函数。
创建S4类和对象
setClass() 命令被用来创建S4类。以下是setclass命令的语法,它用包含名称和rollno的槽来表示我的类。
语法
setClass("myclass", slots=list(name="character", Roll_No="numeric")
new() 函数用于创建一个S4类的对象。在这个函数中,我们将传递类的名称以及槽的值。
例子
输出
从生成器函数创建S4对象
setClass()返回一个生成器函数,该函数有助于创建对象,它就像一个构造函数。
例子
输出
现在,上述创建的stud函数将作为学生类的构造函数。它将表现为new()函数。
例子
输出
S4类中的继承性
R编程中的S4类有适当的定义,派生类将能够继承其基类的属性和方法。为此,我们将首先创建一个带有适当槽的基类,并为该类创建一个通用函数。然后我们将创建一个派生类,它将使用包含参数来继承。派生类将继承基类中的成员和函数。
例子
输出
同时定义S3和S4类的原因 如下。
- 如果直接调用S3泛型函数,将不会单独看到S4类。例如,如果某个函数从一个包中调用 unique() ,而这个包并没有让该函数成为S4泛型,就会出现这种情况。
- 然而,原始函数和运算符是例外。内部C代码将寻找S4方法,如果且仅当对象是一个S4对象。S4方法调度将用于调度任何二进制运算符的调用,其中任何一个操作数是S4对象。
- 如果有任何符合条件的非默认的S4方法,S3类将不会被单独调用。
因此,如果一个包为一个S4类定义了一个唯一的S3方法,但另一个包为该类的超类定义了一个S4方法,那么超类的方法将被选择,可能不是原意。