Подтвердить что ты не робот

Зачем нужны абстрактные классы на С++?

Я только что узнал о полиморфизме в моем классе ООП, и мне трудно понять, насколько полезны абстрактные базовые классы.

Какова цель абстрактного класса? Что обеспечивает определение абстрактного базового класса, которое не предоставляется путем создания каждой необходимой функции в каждом фактическом классе?

4b9b3361

Ответ 1

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

Абстрактные классы не имеют экземпляров. Абстрактный класс должен иметь как минимум один отложенный метод (или функцию). Для этого в С++ чистая виртуальная функция-член объявляется, но не определена в абстрактном классе:

class MyClass {
    virtual void pureVirtualFunction() = 0;
}

Попытки создать экземпляр абстрактного класса всегда будут приводить к ошибке компилятора.

"Что определяет определение абстрактного базового класса, которое не предусмотрено путем создания каждой необходимой функции в каждом действительном классе?"

Основная идея здесь - повторное использование кода и правильное разделение между классами. Имеет смысл определять функцию один раз в родительском классе, а не определять снова и снова в нескольких подклассах:

class A {
   void func1();
   virtual void func2() = 0;
}

class B : public A {
   // inherits A func1()
   virtual void func2();   // Function defined in implementation file
}

class C : public A {
   // inherits A func1()
   virtual void func2();   // Function defined in implementation file
}

Ответ 2

Наличие абстрактного класса, такого как "Собака" с помощью виртуального метода, такого как "bark", позволяет всем классам, которые наследуют от Dog, иметь код коры, вызываемый таким же образом, хотя кора Beagle реализована иначе, чем у Collie's.

Без общего абстрактного родителя (или, по крайней мере, общего родителя с виртуальным методом коры) было бы трудно сделать следующее:

У вас есть вектор типа Dog, который содержит колли, гончих, немецких овчарок и т.д. и заставляет каждого из них лаять. С Vector of Dogs, который содержит Collies, Beagles, German Shepherds, все, что вам нужно было бы сделать, чтобы сделать их всей корой, - это перебирать в цикле for и называть кору на каждом из них. В противном случае вам придется иметь отдельный вектор колли, вектор бигов и т.д.

Если вопрос заключается в том, "почему сделать абстрактную тему Собаки, когда это может быть конкретным, иметь виртуальную кору, определенную с реализацией по умолчанию, которую можно переопределить?", ответ будет заключаться в том, что это может быть приемлемо иногда, но, проектная перспектива, на самом деле нет такой вещи, как Собака, которая не является колли или биглем или какой-либо другой породой или микс, поэтому, хотя все они собаки, в действительности нет ни одного из них, это собака, но не некоторые другие производные классы тоже. Кроме того, поскольку лай собак настолько разнообразен от одной породы к другой, вряд ли будет какая-либо реальная приемлемая реализация коры, которая приемлема для любой достойной группы собак.

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

Ответ 3

Абстрактные классы допускают принудительное выполнение протокола компиляции. Эти протоколы определяют, что значит быть частью семейства классов.

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

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

Ответ 4

Цель абстрактного класса - предоставить соответствующий базовый класс, из которого могут наследовать другие классы. Абстрактные классы не могут использоваться для создания объектов и служат только как интерфейс. Попытка создать экземпляр объекта абстрактного класса вызывает ошибку компиляции. (поскольку запись vtable не заполнена ячейкой памяти для виртуальной функции, о которой мы упоминали в абстрактном классе)

Таким образом, если необходимо создать подкласс ABC, он должен реализовать каждую из виртуальных функций, что означает, что он поддерживает интерфейс, объявленный ABC. Невозможность переопределить чистую виртуальную функцию в производном классе, а затем попытаться создать объекты этого класса, является ошибкой компиляции.

Пример:

class mobileinternet
{
public:
virtual enableinternet()=0;//defines as virtual so that each class can overwrite
};


class 2gplan : public mobileinternet

{
    private:

         int providelowspeedinternet(); //logic to give less speed.

    public:

         void enableinternet(int) {
                                     // implement logic
                                 }

};

//similarly

class 3gplan : public enableinternet
{
   private: high speed logic (different then both of the above)

   public: 
          /*    */
}

здесь, в этом примере, вы можете понять.

Ответ 5

У меня есть собака. Абстрактная собака класса с методом коры. Моя особая собака делает одну кору. Другие собаки лают по-другому. Поэтому определение собаки абстрактным образом полезно.

Ответ 7

Абсолютный класс AbstractClass в качестве базового класса необходим, когда есть функциональность, которая требуется для всех объектов, которые имеют тип, полученный из AbstractClass, но не могут быть разумно реализованы в самом AbstractClass.

Старый и несколько искусственный пример OO с базовым классом Vehicle с производными классами Car, Motorcycle,... дает хороший пример здесь, например, вы хотите использовать метод move() - вы можете реализовать способ, которым перемещаются a Car или Motorcycle, но Vehicle не перемещается в общем виде, поэтому Vehicle::move() должен быть чистым виртуальным и Vehicle поэтому абстрактным.

Ответ 8

почему мы не создаем каждую необходимую функцию в каждом классе? (С++)

Вы должны создать каждую необходимую функцию, помеченную как abstract в каждом производном классе.

Если вы задаетесь вопросом, зачем создавать абстрактную функцию в абстрактном классе?

Он допускает строгий полиморфизм времени выполнения.

Также читайте Интерфейс против абстрактного класса (общий OO)

Ответ 9

abstract class dog
{
bark();
}

// function inside another module

dogbarking(dog obj)
{
   dog.bark(); // function will call depend up on address inside the obj
}


// our class
ourclass: inherit dog
{
    bark()
    {
         //body
     }
}


main()
{
    ourclass obj;
    dogbarking(obj);
}

мы видим, что dogbarking - это функция, написанная в другом модуле. он знает только собаку абстрактного класса. даже если он может вызвать функцию коры внутри нашего класса. в основной функции мы создаем объект нашего класса и переходим к функции dogbarking, где он получен с использованием ссылочного объекта абстрактной собаки класса.

Ответ 10

Представьте, что у вас есть два способа отображения строки:

DisplayDialog(string s);
PrintToConsole(string s);

И вы хотите написать код, который можно переключить между этими двумя способами:

void foo(bool useDialogs) {
    if (useDialogs) {
        DisplayDialog("Hello, World!");
    } else {
        PrintToConsole("Hello, World!");
    }

    if (useDialogs) {
        DisplayDialog("The result of 2 * 3 is ");
    } else {
        PrintToConsole("The result of 2 * 3 is ");
    }

    int i = 2 * 3;
    string s = to_string(i);

    if (useDialogs) {
        DisplayDialog(s);
    } else {
        PrintToConsole(s);
    }        
}

Этот код тесно связан с конкретными методами, используемыми для отображения строки. Добавление дополнительного метода, изменение способа выбора и т.д. Повлияет на каждый фрагмент кода, который использует это. Этот код тесно связан с набором методов, которые мы используем для отображения строк.

Абстрактные базовые классы - это способ развязывания кода, который использует некоторые функции из кода, реализующего эту функциональность. Он делает это, определяя общий интерфейс для всех различных способов выполнения задачи.

class AbstractStringDisplayer {
public:
    virtual display(string s) = 0;

    virtual ~AbstractStringDisplayer();
};

void foo(AbstractStringDisplayer *asd) {
    asd->display("Hello, World!");
    asd->display("The result of 2 * 3 is ");

    int i = 2 * 3;
    string s = to_string(i);

    asd->display(s);
}

int main() {
    AbstractStringDisplayer *asd = getStringDisplayerBasedOnUserPreferencesOrWhatever();

    foo(asd);
}

Используя интерфейс, определенный AbstractStringDisplayer, мы можем создавать и использовать столько новых способов отображения строк, сколько хотим, и код, который использует абстрактный интерфейс, не нуждается в изменении.