> For the complete documentation index, see [llms.txt](https://evgenii-afanasev.gitbook.io/ruby-course/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://evgenii-afanasev.gitbook.io/ruby-course/3_oop/3_inheritance.md).

# Наследование

Наследование в Ruby - это концепция объектно-ориентированного программирования, которая позволяет новым классам использовать свойства существующего класса. Это позволяет упрощать код и повторно использовать уже написанный код.

Давайте рассмотрим следующий пример:

```ruby
class Vehicle
  def initialize(make, model, year)
    @make = make
    @model = model
    @year = year
  end

  def drive
    puts "Driving the vehicle"
  end

  def info
    "#{@make} #{@model}, #{year}"
  end
end
```

```ruby
# Знак '<' обозначает, что Car наследует Vehicle
class Car < Vehicle
  def initialize(make, model, year, doors)
    # вызываем конструктор у родительского класса
    super(make, model, year)
    # переменная класса Car, которая не является частью Vehicale
    @doors = doors
  end

  def drive
    puts "Driving the car"
  end
end
```

Здесь класс `Vehicle` имеет метод `drive`, который может быть вызван из любого объекта, созданного на основе этого класса. Класс `Car`, который наследует `Vehicle`, добавляет новое свойство `doors`, но также имеет доступ ко всем методам класса `Vehicle`, которые могут быть использованы в любом объекте, созданном на основе класса `Car`, а также имеет такой же метод `drive`, как и в родителе, но при этом уже с другой логикой. Это называется **переопределение метода родителя**. Метод `super` вызывает конструктор родительского класса, что позволяет наследующему классу добавлять новые свойства и методы, используя свойства и методы родительского класса.

Посмотрим на пример использования:

```ruby
vehicle = Vehicle.new(:Audi, :A80, 2010)
p vehicle # = Vehicle(make = audi, model = A80, year = 2010)
car = Car.new(:BMW, :X5, 2020, 4) 
p car # = Car(make = audi, model = A80, year = 2010, doors = 4)

puts vehicle.info # = Audi A80, 2010
# Как мы видим метод info мы не определяли в классе Car, при этом его поведение ничем не отличается от поведение родителя
puts car.info # = BMW X5, 2020

vehicle.drive # = Driving the vehicle
# Заметьте, поведение метода поменялось
car.drive # = Driving the car
```

Ранее мы также говорили о константах и переменных класса, настало время поговорить о том, почему их использование вредит программе. Как мы помним, в Ruby абсолютно все является объектами. Даже сам класс который мы создаем это тоже объект. Каждый раз, когда мы наследуем класс от другого класса мы помимо методов и атрибутов объекта родителя наследуем еще и методы и атрибуты класса.

```ruby
class Person
  @@count = 0

  # метод класса, чтобы мы могли прочитать значение атрибута класса
  def self.count
    @@count
  end

  def initialize(name)
    @@count += 1
    @name = name
  end
end
```

```ruby
class Vampir < Person
  def initialize(name)
    super(name)
  end
end
```

```ruby
mike = Person.new('Mike')
john = Vampir.new('dracula')

# Казалось бы наш класс должен был получить собственную переменную класса
# а на самом деле наш новый класс получает доступ к переменной совершенно другого класса
p Person.count # = 2
```

Помимо переменных и методов класса наследуются также и приватные методы.

Возможно проблема может показаться небольшой, но представьте себе, что у вас не 1 наследник, а 10 и каждый из наследников будет посвоему менять переменную класса, в результате мы будем в каждом нашем наследнике получать совершенно непредсказуемое значение. Всегда помните про эту особенность, так как это поможет сделать вашу программу более надежной + на собеседовании любят поспрашивать глубоко про наследование классов и поведение таких переменных.

## Задание animals

**Внимание ! Это и последующие задания данного модуля с названием `canimalsat` необходимо выполнять в одной и той же директории в корне модуля - `3_oop/animals`**

* Создайте новый класс `Dog`, который будет наследовать класс кота.
* Переопределите метод `voice`, чтобы вместо печати в консоль `Meow`, печаталось `Woof`.

## Задание bank

* реализуйте родительский класс `BankAccount` со следующими методами:
  * `get_amount` - возвращает баланс счета
  * `put` - пополнение баланса без комиссии
  * `take` - Спасание средств с баланса без комиссии. Если передать в метод пополнения отрицательное значение, сумма на счёте не должна измениться. При попытке снять большую сумму, чем есть на счёте, сумма не списывается со счёта, сумма на счёте не изменяется.
* Создайте класс-наследник `CardAccount`- карточный счёт, в дополнение к условиям `BankAccount` — при снятии денег должна взиматься комиссия 1% от суммы списания. Пример: при попытке снять со счёта 100 рублей должен списаться 101 рубль.
* Создайте класс-наследник `DepositAccount` - депозитный расчётный счёт, в дополнение к условиям BankAccount — нельзя снимать деньги в течение одного месяца после последнего пополнения. Переменную, в которой хранится дата последнего внесения, назовите last\_income.

## Дополнительный материал

* [Наследование в Ruby](https://www.rubyguides.com/2019/01/what-is-inheritance-in-ruby/)
* [Наследование переменных класса](https://stackoverflow.com/questions/1251352/ruby-inherit-code-that-works-with-class-variables)
