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

Наследование в 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://evgenii-afanasev.gitbook.io/ruby-course/3_oop/3_inheritance.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
