JS ++ | Абстрактные классы и методы

Опубликовано: 10 Апреля, 2022

Мы изучили виртуальные методы, а также «перезапись» (раннее связывание) и «переопределение» (позднее связывание), которые позволяют нам определять базовые реализации для метода и более конкретные реализации метода в подклассах. Однако что нам делать, если нет соответствующей базовой реализации, которая имеет смысл? Рассмотрим метод «разговора». Что будет делать базовый класс «Животное», пока «собака» будет «гавкать», а «кошка» - «мяукать»? Абстрактные классы и методы позволяют решить эту проблему.

Когда класс объявлен с модификатором 'abstract', он не может быть создан. Более того, это позволяет классу иметь «абстрактные методы». Абстрактные методы - это методы, которые не определяют реализацию, и реализация предоставляется производным классам. Производные классы должны реализовывать все абстрактные методы при наследовании от абстрактного класса; в противном случае мы получим ошибку компиляции.

Начнем с того, что сделаем наш класс Animal в Animal.jspp абстрактным и объявим абстрактный метод talk:

внешний $;

модуль Животные
{
    абстрактный класс Animal
    {
        защищенный элемент var $;
        частный статический беззнаковый int count = 0;

        protected Animal (string iconClassName) {
            строковый элементHTML = makeElementHTML (iconClassName);
            $ element = $ (elementHTML);

            Animal.count ++;
        }

        public static unsigned int getCount () {
            return Animal.count;
        }

        public virtual void render () {
            $ ("# содержание"). append ($ element);
        }

        public abstract void talk ();

        частная строка makeElementHTML (строка iconClassName) {
            строка result = '<div class = "animal">';
            результат + = '<i class = "icofont' + iconClassName + '"> </i>';
            результат + = "</div>";
            вернуть результат;
        }
    }
}

Если мы попытаемся скомпилировать прямо сейчас, мы получим ошибки компилятора, требующие, чтобы подклассы Animal реализовали абстрактный метод talk.

Начнем с Cat.jspp:

import Externals.DOM;

external $;

module Animals
{
    class Cat : Animal
    {
        string _name;

        Cat(string name) {
            super("icofont-animal-cat");
            _name = name;
        }

        final void render() {
            $element.attr("title", _name);
            super.render();
        }

        final void talk() {
            alert("Meow!");
        }
    }
}

Мы импортируем Externals.DOM, потому что этот модуль предоставляет все «внешние» объявления для API DOM (объектной модели документа) для браузеров. Это позволяет нам использовать функцию «оповещения», которая выводит всплывающее окно сообщения с тем, что мы хотим, чтобы кошка сказала («Мяу!»). Мы также могли бы просто объявить «предупреждение» как «внешнее». Обратите внимание, что мы использовали модификатор final, чтобы переопределить слово talk, но с таким же успехом можно было бы использовать override.

Мы собираемся реализовать Dog.jspp аналогично, но собаки издают другой звук:

import Externals.DOM;

внешний $;

модуль Животные
{
    класс Собака: Животное
    {
        строка _name;

        Dog (название строки) {
            супер («икофонт-животное-собака»);
            _name = имя;
        }

        final void render () {
            $ element.attr ("название", _name);
            super.render ();
        }

        final void talk () {
            alert («Гав!»);
        }
    }
}

Теперь давайте реализуем Panda.jspp. Панды умеют лаять, так что давайте заставим их лаять:

import Externals.DOM;

внешний $;

модуль Животные
{
    класс Панда: Животное
    {
        Panda () {
            супер («икофонт-животное-панда»);
        }

        final void talk () {
            alert («Лай!»);
        }
    }
}

Последний класс, который нужно реализовать: «Rhino». Предположим, носороги не издают ни звука. Совершенно нормально просто переопределить абстрактный метод и ничего не делать:

внешний $;

модуль Животные
{
    класс Rhino: Animal
    {
        Rhino () {
            супер («икофонт-животное-носорог»);
        }

        final void talk () {
        }
    }
}

Обратите внимание, что мы также не импортировали Externals.DOM. Нам это было не нужно. Наш носорог не разговаривает, поэтому нам не нужна функция предупреждения для отображения окна сообщения.

На этом этапе ваш проект должен быть скомпилирован без ошибок. Однако на самом деле наши животные пока не разговаривают. Нам нужно какое-то событие, чтобы животное заговорило. Например, мы можем захотеть, чтобы животное разговаривало, когда мы нажимаем на него. Для этого нам нужны обработчики событий, и это тема следующего раздела.