为什么我们需要 C++ 中的抽象类?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14189438/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do we need abstract classes in C++?
提问by Yoshua Joo Bin
I've just learned about polymorphism in my OOP Class and I'm having a hard time understanding how abstract base classes are useful.
我刚刚在我的 OOP 类中了解了多态性,但我很难理解抽象基类是如何有用的。
What is the purpose of an abstract class? What does defining an abstract base class provide that isn't provided by creating each necessary function in each actual class?
抽象类的目的是什么?定义一个抽象基类提供了什么,而不是通过在每个实际类中创建每个必要的函数来提供?
回答by Chris Dargis
The purpose of an abstract class is to define a common protocol for a set of concrete subclasses. This is useful when defining objects that share code, abstract ideas, etc.
抽象类的目的是为一组具体的子类定义一个通用协议。这在定义共享代码、抽象想法等的对象时很有用。
Abstract classes have no instances. An abstract class must have at least one deferred method (or function). To accomplish this in C++, a pure virtual member function is declared but not defined in the abstract class:
抽象类没有实例。一个抽象类必须至少有一个延迟的方法(或函数)。为了在 C++ 中实现这一点,在抽象类中声明了一个纯虚成员函数,但没有定义:
class MyClass {
virtual void pureVirtualFunction() = 0;
}
Attempts to instantiate an abstract class will always result in a compiler error.
尝试实例化抽象类总是会导致编译器错误。
"What does defining an abstract base class provide that isn't provided by creating each necessary function in each actual class?"
“通过在每个实际类中创建每个必要的函数,定义一个抽象基类提供了什么?”
The main idea here is code reuse and proper partitioning across classes. It makes more sense to define a function once in a parent class rather than defining over and over again in multiple subclasses:
这里的主要思想是代码重用和跨类的适当分区。在父类中定义一次函数比在多个子类中一遍又一遍地定义更有意义:
class A {
void func1();
virtual void func2() = 0;
}
class B : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
class C : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
回答by Chris
Having an abstract class like "Dog" with a virtual method like "bark" allows all classes that inherit from Dog to have their bark code called in the same way, even though the Beagle's bark is implemented way differently than the Collie's.
拥有像“Dog”这样的抽象类和像“bark”这样的虚方法,允许所有继承自 Dog 的类以相同的方式调用它们的 bark 代码,即使 Beagle 的 bark 的实现方式与 Collie 的不同。
Without a common abstract parent (or at least a common parent with a bark virtual method) it'd be difficult to do the following:
如果没有一个共同的抽象父级(或者至少是一个带有 bark 虚拟方法的共同父级),就很难做到以下几点:
Have a Vector of type Dog that contains Collies, Beagles, German Shepherds etc and make each of them bark. With a Vector of Dogs that contains Collies, Beagles, German Shepherds all you would have to do to make them all bark is to iterate through in a for loop and call bark on each one. Otherwise you'd have to have a separate Vector of Collies, Vector of Beagles etc.
有一个 Dog 类型的 Vector,其中包含牧羊犬、比格犬、德国牧羊犬等,并使它们每一个都吠叫。使用包含牧羊犬、比格犬、德国牧羊犬的 Vector of Dogs,您只需在 for 循环中迭代并调用 bark 即可让它们全部吠叫。否则,您必须有一个单独的牧羊犬矢量、比格犬矢量等。
If the question is "why make Dog abstract when it could be concrete, have a virtual bark defined with a default implementation that can be overriden?", the answer would be that this may be acceptable sometimes -- but, from a design perspective, there really isn't any such thing as a Dog that isn't a Collie or a Beagle or some other breed or mix so although they are all Dogs, there is not one of them in reality that is a Dog but not some other derived class too. Also, since dogs barking is so varied from one breed to another, there is unlikely to be any real acceptable default implementation of bark that would be acceptable for any decent group of Dogs.
如果问题是“为什么在 Dog 可以是具体的情况下将其抽象化,使用可以覆盖的默认实现定义一个虚拟树皮?”,答案是有时这可能是可以接受的 - 但是,从设计的角度来看,真的没有任何狗不是牧羊犬或小猎犬或其他品种或混合所以尽管它们都是狗,但实际上没有一个是狗,而不是其他衍生品类也是。此外,由于狗的吠叫因品种而异,因此不太可能有任何真正可接受的默认吠叫实现,这对于任何体面的狗来说都是可以接受的。
I hope this helps you understand the purpose: yes, you're going to have to implement bark in each subclass anyway, but the common abstract ancestor lets you treat any subclass as a member of a base class and invoke behaviors that may be conceptually similar like bark but in fact have very different implementations.
我希望这可以帮助您理解目的:是的,无论如何您都必须在每个子类中实现 bark,但是公共抽象祖先允许您将任何子类视为基类的成员并调用可能在概念上相似的行为像 bark 但实际上有非常不同的实现。
回答by sean
Abstract classes allow for compile time protocol enforcement. These protocols define what it means to be a part of a class family.
抽象类允许编译时协议强制执行。这些协议定义了成为类家族的一部分意味着什么。
Another way to think of it is that a abstract class is a contract that your implementing classes must fulfill. If they do not fulfill this contract they cannot be part of the class family and they must be modified to conform to the contract. The provided contract may provide default functionality, but it also leaves it up to the sub-class to define more specific or different functionality while still remaining within the scope of the contract.
另一种思考方式是,抽象类是您的实现类必须履行的契约。如果他们不履行这个合同,他们就不能成为班级家庭的一部分,他们必须被修改以符合合同。提供的合约可以提供默认功能,但它也让子类来定义更具体或不同的功能,同时仍保持在合约的范围内。
For small projects this may not seem useful but for large projects it provides conformity and structure as it provides documentation through the abstract class contract. This makes for more maintainable code and makes for the sub-classes to each have the same protocol making using and developing new sub-classes easier.
对于小型项目,这似乎没有用,但对于大型项目,它提供了一致性和结构,因为它通过抽象类合同提供文档。这使得代码更易于维护,并使每个子类具有相同的协议,从而更容易使用和开发新的子类。
回答by Venkatakrishna Kalepalli
The purpose of an abstract class is to provide an appropriate base class from which other classes can inherit. Abstract classes cannot be used to instantiate objects and serves only as an interface. Attempting to instantiate an object of an abstract class causes a compilation error. (because vtable entry is not filled with memory location for virtual function we mentioned in Abstract Class)
抽象类的目的是提供一个合适的基类,其他类可以从中继承。抽象类不能用于实例化对象,只能用作接口。尝试实例化抽象类的对象会导致编译错误。(因为vtable条目没有填充我们在抽象类中提到的虚函数的内存位置)
Thus, if a subclass of an ABC needs to be instantiated, it has to implement each of the virtual functions, which means that it supports the interface declared by the ABC. Failure to override a pure virtual function in a derived class, then attempting to instantiate objects of that class, is a compilation error.
因此,如果需要实例化 ABC 的子类,它必须实现每个虚函数,这意味着它支持由 ABC 声明的接口。未能覆盖派生类中的纯虚函数,然后尝试实例化该类的对象,是编译错误。
Example:
例子:
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:
/* */
}
here in this example, you can understand.
在这个例子中,你可以理解。
回答by Ed Heal
I have a dog. Abstract class dog with a method bark. My particular dog makes one bark. Other dogs bark in a different way. So defining a dog in the abstract way is useful.
我养了一条狗。与方法吠声的抽象类狗。我那只狗叫了一声。其他狗以不同的方式吠叫。所以以抽象的方式定义一只狗是有用的。
回答by us2012
An abstract class AbstractClass
as a base class is needed when there is functionality that is desired for all objects that have a type deriving from AbstractClass
, but cannot sensibly be implemented on the AbstractClass
itself.
AbstractClass
当所有具有派生自 类型的对象都需要功能AbstractClass
但不能在其AbstractClass
自身上明智地实现时,需要一个抽象类作为基类。
The old and somewhat artificial OO example of having a base class Vehicle
with derived classes Car
, Motorcycle
, ... provides a good example here, say you want a method move()
- you can implement the way that a Car
or a Motorcycle
moves, but Vehicle
s don't move in a generic way, so Vehicle::move()
will have to be pure virtual and Vehicle
therefore abstract.
具有基础类的老有点人为OO例如Vehicle
与派生类Car
,Motorcycle
...这里提供了一个很好的例子,假设你想一个方法move()
-你可以实现的方式,一个Car
或一个Motorcycle
动作,但Vehicle
就做不动的一种通用方式,因此Vehicle::move()
必须是纯虚拟的,Vehicle
因此是抽象的。
回答by Tilak
why don't we create each necessary function in each class ? (C++)
为什么我们不在每个类中创建每个必要的功能?(C++)
You have to create each necessary function marked as abstract
in each derived class.
您必须创建abstract
在每个派生类中标记为的每个必要函数。
If you question is, why to create abstract function in abstract class?
如果您的问题是,为什么要在抽象类中创建抽象函数?
It allows strict run time polymorphism.
它允许严格的运行时多态性。
Also read Interface vs Abstract Class (general OO)
另请阅读接口与抽象类(一般面向对象)
回答by OldProgrammer
Abstract classes are used to define an interface to be implemented. See some references:
抽象类用于定义要实现的接口。看一些参考资料:
http://en.wikibooks.org/wiki/C%2B%2B_Programming/Classes/Abstract_Classes
http://en.wikibooks.org/wiki/C%2B%2B_Programming/Classes/Abstract_Classes
回答by Rajesh
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);
}
we can see that dogbarking is a function written in another module. it knows only the abstract class dog. even though it can call the function bark inside ourclass. in main function we create object of ourclass and pass to function dogbarking where it received using reference object of abstract class dog.
我们可以看到 dogbarking 是一个写在另一个模块中的函数。它只知道抽象类狗。即使它可以在我们的类中调用函数 bark。在 main 函数中,我们创建了我们的类的对象并传递给函数 dogbarking,在那里它使用抽象类 dog 的引用对象接收。
回答by bames53
Imagine you have two methods for displaying a string:
想象一下,您有两种显示字符串的方法:
DisplayDialog(string s);
PrintToConsole(string s);
And you want to write some code that can be switched between these two methods:
并且您想编写一些可以在这两种方法之间切换的代码:
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);
}
}
This code is tightly coupled to the specific methods used for displaying the string. Adding an additional method, changing how the method is selected, etc. will affect every piece of code that uses this. This code is tightly coupledto the set of methods we use to display strings.
此代码与用于显示字符串的特定方法紧密耦合。添加额外的方法、改变方法的选择方式等都会影响使用它的每一段代码。这段代码与我们用来显示字符串的一组方法紧密耦合。
Abstract base classes are a way of decouplingcode that uses some functionality from the code that implements that functionality. It does this by defining a common interface to all the various ways of doing the task.
抽象基类是一种将使用某些功能的代码与实现该功能的代码解耦的方法。它通过为完成任务的所有不同方式定义一个通用接口来实现这一点。
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);
}
Using the interface defined by AbstractStringDisplayer we can create and use as many new ways of displaying strings as we want, and code that uses the abstract interface won't need to be changed.
使用 AbstractStringDisplayer 定义的接口,我们可以根据需要创建和使用任意多种显示字符串的新方式,并且不需要更改使用抽象接口的代码。