Menu
Coddy logo textTech

containsで拡張する

CoddyのRジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 32/57。

contains = "Animal" は、新しい S4 クラスを Animal のサブクラスにします。サブクラスは親クラスのすべてのスロットに加えて独自のスロットも持ち、new() はそれらすべてを受け取ります:

setClass("Animal", slots = c(name = "character", age = "numeric"))
setClass("Dog", contains = "Animal", slots = c(breed = "character"))
rex <- new("Dog", name = "Rex", age = 3, breed = "collie")
print(slotNames("Dog"))
cat(rex@name, rex@breed)

出力:

[1] "breed" "name"  "age"  
Rex collie

親クラス用に書かれたメソッドは、子クラスにも機能します。ジェネリックに対してDog用のメソッドがない場合、S4はAnimal用のメソッドを使用します:

setClass("Animal", slots = c(name = "character"))
setClass("Dog", contains = "Animal")
invisible(setGeneric("intro", function(a) standardGeneric("intro")))
setMethod("intro", "Animal", function(a) paste("I am", a@name))
print(intro(new("Dog", name = "Rex")))

出力:

[1] "I am Rex"

子クラスは、同じジェネリックに対して独自のメソッドを定義することで、親クラスのメソッドをオーバーライドします。最も具体的なクラスが優先され、他のサブクラスは親クラスのメソッドを引き継ぎます:

setClass("Animal", slots = c(name = "character"))
setClass("Dog", contains = "Animal")
setClass("Cat", contains = "Animal")
invisible(setGeneric("sound", function(a) standardGeneric("sound")))
setMethod("sound", "Animal", function(a) "...")
setMethod("sound", "Dog", function(a) "woof")
cat(sound(new("Dog", name = "Rex")), sound(new("Cat", name = "Tom")))

出力:

woof ...

is(x, "Animal") は犬に対して TRUE であり、"Animal" として宣言されたスロットは Dog を受け入れます。親クラス用に書かれたコードは、すべてのサブクラスで動作します。

setClass("Animal", slots = c(name = "character"))
setClass("Dog", contains = "Animal")
setClass("Owner", slots = c(pet = "Animal"))
rex <- new("Dog", name = "Rex")
o <- new("Owner", pet = rex)
cat(is(rex, "Animal"), is(o@pet, "Dog"))

出力:

TRUE TRUE
challenge icon

チャレンジ

簡単

従業員とマネージャーは、2つのファイルに分けられたS4クラスです。Employee.Rでは、Employee(スロットname、salary)とジェネリック関数describe()を宣言し、Employeeに対してBo earns 40000を返すメソッドが必要です。Manager.Rでは、Employeeを含み、スロットreports(numeric)を追加するManagerを宣言し、describe()をオーバーライドしてAda earns 60000 and manages 4を返すようにします。

用意されたコードは、employee Bo 40000またはmanager Ada 60000 4の行を読み込み、describe()の結果、オブジェクトが従業員かどうか、およびそのスロットを出力します。

コードはEmployee.RとManager.Rに記述します。main.Rには用意された入出力コードが含まれており、編集できません。

自分で試してみよう

source("Employee.R")
source("Manager.R")

# 提供された入出力コード: そのままにしておく
input <- suppressWarnings(readLines(file("stdin")))
for (line in input) {
  p <- strsplit(line, " ")[[1]]
  x <- if (p[1] == "manager") {
    new("Manager", name = p[2], salary = as.numeric(p[3]), reports = as.numeric(p[4]))
  } else {
    new("Employee", name = p[2], salary = as.numeric(p[3]))
  }
  cat(describe(x), "\n", sep = "")
  cat("is an employee: ", is(x, "Employee"), ", slots: ", paste(slotNames(x), collapse = ", "), "\n", sep = "")
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Rオンラインコンパイラ