Зачем нужны абстрактные классы на С++?
Я только что узнал о полиморфизме в моем классе ООП, и мне трудно понять, насколько полезны абстрактные базовые классы.
Какова цель абстрактного класса? Что обеспечивает определение абстрактного базового класса, которое не предоставляется путем создания каждой необходимой функции в каждом фактическом классе?
Ответы
Ответ 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
У меня есть собака. Абстрактная собака класса с методом коры. Моя особая собака делает одну кору. Другие собаки лают по-другому. Поэтому определение собаки абстрактным образом полезно.
Ответ 6
Абстрактные классы используются для определения интерфейса, который должен быть реализован. См. Некоторые ссылки:
http://en.wikibooks.org/wiki/C%2B%2B_Programming/Classes/Abstract_Classes
Ответ 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, мы можем создавать и использовать столько новых способов отображения строк, сколько хотим, и код, который использует абстрактный интерфейс, не нуждается в изменении.