end
# ...
end
А класс Student
— так:
class Student < Person
attr_accessor :idnum, :hours
def initialize(name, age, sex, idnum, hours)
super(name, age, sex)
@idnum = idnum
@hours = hours
end
# ...
end
# Создать два объекта.
a = Person.new('Dave Bowman', 37, 'm')
b = Student.new('Franklin Poole', 36, 'm', '000-13-5031', 24)
Посмотрим внимательно, что здесь сделано. Что за super
, вызываемый из метода initialize
класса Student
? Это просто вызов соответствующего метода родительского класса. А раз так, то ему передается три параметра (хотя наш собственный метод initialize
принимает пять).
Не всегда необходимо использовать слово super
подобным образом, но часто это удобно. В конце концов, атрибуты любого класса образуют надмножество множества атрибутов его родительского класса, так почему не воспользоваться для их инициализации конструктором родительского класса?
Если говорить об истинном смысле наследования, то оно, безусловно, описывает отношение «является». Студент является человеком, как и следовало ожидать. Сделаем еще три замечания:
• Каждый атрибут (и метод) родительского класса отражается в его потомках. Если в классе Person
есть атрибут height
, то класс Student
унаследует его, а если родитель имеет метод say_hello
, такой метод будет и у потомка.
• Потомок может иметь дополнительные атрибуты и методы, мы это только что видели. Поэтому создание подкласса часто еще называют
• Потомок может переопределять любые атрибуты и методы своего родителя.
Последнее замечание подводит нас к вопросу о том, как разрешается вызов метода. Откуда я знаю, вызывается ли метод конкретного класса или его суперкласса?
Краткий ответ таков: не знаю и не интересуюсь. Если вызывается некий метод от имени объекта класса Student
, то будет вызван метод, определенный в этом классе, если он существует. А если нет, вызывается метод суперкласса и так далее вверх по иерархии наследования. Мы говорим «и так далее», потому что у каждого класса (кроме Object
) есть суперкласс.
А что если мы хотим вызвать метод суперкласса, но не из соответствующего метода подкласса? Можно сначала создать в подклассе синоним:
class Student # Повторное открытие класса.
# Предполагается, что в классе Person есть метод say_hello...
alias :say_hi :say_hello
def say_hello
puts 'Привет.'
end
def formal_greeting
# Поприветствовать так, как принято в суперклассе.
say_hi
end
end
У наследования есть разные тонкости, которых мы здесь касаться не будем. Общий принцип мы изложили, но не пропустите следующий раздел.
11.1.6. Опрос класса объекта
Часто возникает вопрос: «Что это за объект? Как он соотносится с данным классом?» Есть много способов получить тот или иной ответ.
Во-первых, метод экземпляра class
всегда возвращает класс объекта. Применявшийся ранее синоним type
объявлен устаревшим.
s = 'Hello'
n = 237
sc = s.class # String
nc = n.class # Fixnum
He думайте, будто методы class
или type
возвращают строку, представляющую имя класса. На самом деле возвращается экземпляр класса Class
! При желании мы могли бы вызвать метод класса, определенный в этом типе, как если бы это был метод экземпляра класса Class
(каковым он в действительности и является).
s2 = 'some string'
var = s2.class # String
my_str = var.new('Hi...') # Новая строка.
Можно сравнить такую переменную с константным именем класса и выяснить, равны ли они; можно даже использовать переменную в роли суперкласса и определить на ее основе подкласс! Запутались? Просто помните, что в Ruby Class
— это объект, a Object
— это класс.
Иногда нужно сравнить объект с классом, чтобы понять, принадлежит ли данный объект указанному классу. Для этого служит метод instance_of?
, например:
puts (5.instance_of? Fixnum) # true
puts ('XYZZY'.instance_of? Fixnum) # false
puts ('PLUGH'.instance_of? String) # true
А если нужно принять во внимание еще и отношение наследования? К вашим услугам метод kind_of?
(похожий на instance_of?
). У него есть синоним is_a?
, что вполне естественно, ибо мы описываем классическое отношение «является».
n = 9876543210
flag1 = n.instance_of? Bignum # true
flag2 = n.kind_of? Bignum # true