Menu
Coddy logo textTech

상속과 callSuper

Coddy R 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 57개 중 40번째.

contains = "Account"는 Reference Class가 Account의 모든 필드와 메서드를 상속하도록 합니다. 서브클래스는 자체 필드와 메서드를 추가합니다:

Account <- suppressMessages(setRefClass("Account",
  fields = list(owner = "character", balance = "numeric"),
  methods = list(deposit = function(x) balance <<- balance + x)
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
  fields = list(rate = "numeric"),
  methods = list(add_interest = function() deposit(balance * rate))
))
s <- Savings$new(owner = "Ada", balance = 100, rate = 0.05)
s$deposit(100)
s$add_interest()
cat(s$balance, is(s, "Account"))

출력:

210 TRUE

하위 클래스는 같은 이름의 메서드를 정의하여 메서드를 재정의합니다. 그 안에서 callSuper(...)는 부모 클래스의 버전을 호출하므로, 자식 클래스는 새로 추가되는 부분만 더합니다:

Account <- suppressMessages(setRefClass("Account",
  fields = list(balance = "numeric"),
  methods = list(withdraw = function(x) {
    if (x > balance) stop("insufficient funds", call. = FALSE)
    balance <<- balance - x
  })
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
  methods = list(withdraw = function(x) {
    if (x > 500) stop("limit is 500", call. = FALSE)
    callSuper(x)
  })
))
s <- Savings$new(balance = 300)
s$withdraw(200)
for (x in c(600, 400)) cat(tryCatch({ s$withdraw(x); "ok" }, error = function(e) conditionMessage(e)), "\n")
cat(s$balance, "\n")

출력:

limit is 500 
insufficient funds 
100 

initialize는 다른 메서드와 마찬가지로 상속되고 재정의됩니다. 자식의 initialize는 부모가 필드를 설정하도록 callSuper(...)를 호출한 다음, 자체 기본값을 설정합니다.

Account <- suppressMessages(setRefClass("Account",
  fields = list(owner = "character", balance = "numeric"),
  methods = list(initialize = function(...) {
    initFields(...)
    if (length(balance) == 0) balance <<- 0
    invisible(.self)
  })
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
  fields = list(rate = "numeric"),
  methods = list(initialize = function(...) {
    callSuper(...)
    if (length(rate) == 0) rate <<- 0.01
    invisible(.self)
  })
))
s <- Savings$new(owner = "Bo")
cat(s$owner, s$balance, s$rate)

출력:

Bo 0 0.01

서로 다른 하위 클래스의 객체는 동일한 메서드 호출에 각자의 방식으로 응답하므로, 혼합된 목록을 순회하는 루프에는 클래스 검사가 필요하지 않습니다:

Account <- suppressMessages(setRefClass("Account",
  fields = list(balance = "numeric"),
  methods = list(month_end = function() balance <<- balance - 2)
))
Savings <- suppressMessages(setRefClass("Savings", contains = "Account",
  methods = list(month_end = function() balance <<- balance * 1.01)
))
bank <- list(Account$new(balance = 100), Savings$new(balance = 100))
for (a in bank) a$month_end()
cat(vapply(bank, function(a) a$balance, numeric(1)))

출력:

98 101
challenge icon

챌린지

쉬움

계정과 저축 계정은 두 파일에 있는 Reference Class입니다. 메서드를 완성하세요:

  • Account의 Account.R (필드 owner, balance): initialize는 잔액이 주어지지 않은 경우 잔액을 0으로 설정합니다. deposit(x); withdraw(x)는 insufficient funds와 함께 중단됩니다. month_end()는 1의 수수료를 차감합니다. describe()는 ada: 99를 반환합니다.
  • Savings의 Savings.R (Account를 포함하며, 필드 rate): withdraw(x)는 500 초과 시 limit is 500과 함께 중단되고, 그렇지 않으면 callSuper(x)를 호출합니다. month_end()는 수수료 대신 이자인 balance * rate를 더합니다. describe()는 callSuper()와 함께 (savings)를 추가합니다.

call. = FALSE를 사용하세요. 두 정의 모두 suppressMessages()로 감싸져 있습니다. 제공된 코드는 savings ada 0.1 또는 account bo를 읽은 다음, dep 100, wd 30 또는 month를 읽고 각 항목 뒤에 describe() 또는 refused: 와 메시지를 출력합니다.

코드는 Account.R과 Savings.R에 작성합니다. main.R에는 제공된 입력/출력 코드가 들어 있으며 편집할 수 없습니다.

직접 해보기

source("Account.R")
source("Savings.R")

# 제공된 입력/출력 코드: 그대로 유지하세요
input <- suppressWarnings(readLines(file("stdin")))
p <- strsplit(input[1], " ")[[1]]
acc <- if (p[1] == "savings") Savings$new(owner = p[2], rate = as.numeric(p[3])) else Account$new(owner = p[2])
for (line in input[-1]) {
  q <- strsplit(line, " ")[[1]]
  msg <- tryCatch({
    if (q[1] == "dep") acc$deposit(as.numeric(q[2]))
    if (q[1] == "wd") acc$withdraw(as.numeric(q[2]))
    if (q[1] == "month") acc$month_end()
    acc$describe()
  }, error = function(e) paste("refused:", conditionMessage(e)))
  cat(line, ": ", msg, "\n", sep = "")
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 R 컴파일러