C++ 为什么我要实现虚拟函数而不在抽象类中实现?

C++ 为什么我要实现虚拟函数而不在抽象类中实现?,c++,abstract-class,virtual,C++,Abstract Class,Virtual,对不起,我得问一个愚蠢的问题。 我理解实现抽象类的好处。如果我有一个基本实现的虚拟函数,它总是在派生类没有特定实现的情况下被调用,那么肯定会有好处,例如。 virtualvoid ImplementedVirtFunc(){//do something basic} 我不太明白的是,实现一个纯粹的虚拟函数,比如 virtualvoid VirtFunc()=0 在这种情况下,如果需要,我的派生类无论如何都需要实现专门化的函数。但是我可以直接在那里实现它,并在我的抽象类中省略虚拟void Virt

对不起,我得问一个愚蠢的问题。 我理解实现抽象类的好处。如果我有一个基本实现的虚拟函数,它总是在派生类没有特定实现的情况下被调用,那么肯定会有好处,例如。
virtualvoid ImplementedVirtFunc(){//do something basic}

我不太明白的是,实现一个纯粹的虚拟函数,比如
virtualvoid VirtFunc()=0

在这种情况下,如果需要,我的派生类无论如何都需要实现专门化的函数。但是我可以直接在那里实现它,并在我的抽象类中省略
虚拟void VirtFunc()=0

那么实现
virtualvoid VirtFunc()=0
是否有我看不到的特殊好处呢

请原谅我这个愚蠢的问题。今年一月我开始学习C++,我还有很长的路要走,去理解所有的细微之处……
virtual void f();     // virtual member function
virtual void g() = 0; // pure abstract member function
至少有一个纯虚成员函数的类是一个抽象类,不能自行构造,这通常是需要的(只有非抽象的“具体的”,如果您愿意的话,应该能够构造派生类)

抽象类通常以多态方式使用,以允许动态分派到派生对象方法:

struct Derived : public Abstract {
    void g() override {}  // #1
}

void h(Abstract const& obj) {
    obj.g();  // dynamic dispatch
}

int main() {
    Derived d{};
    h(d);  // Will result in invoke #1
}
但我可以直接在那里实现它,并在抽象类中省略虚拟void VirtFunc()=0行

当然可以。但是您不能从基类调用该方法,因为您的基类根本不知道它的存在

考虑下面的例子。每个
形状
肯定都有一个区域,即使一般形状不知道。
Shape
的每个子类都继承了
Print()
方法

类形状{
// ...
公众:
virtual int Area()=0;//对于“一般”形状的面积没有公式,但它肯定有一个公式。。。
虚拟空打印(){

有两个原因。
一种是强制派生的具体类实现虚拟函数。

第二种方法是使您的类成为一个抽象类,而抽象类本身无法实例化。

当基类没有函数的实现,并且您希望强制派生类提供函数时,会使用virtual void VirtFunc()=0
。“但我可以直接在那里实现它。”-如何实现?假设在父类中始终有一种实现“基本版本”的方法,您可以找到大量不可能实现的示例(或者技术上可行但没有意义)。有时,在基类中没有合理的默认行为可以实现。@Jarod42,我认为这取决于实际的用例。抽象类提供了一个框架,因此可能有一些有用的默认实现,也可能没有。一个“有趣的”事情是,您可以将虚拟函数声明为“纯”-因此需要重写-并在同一个类中为其提供定义。不过,我不记得我是否见过它的良好用途。仅当派生类本身希望成为非抽象类(通常情况下)时,派生类本身不会被迫实现虚函数。多接口继承并不少见(例如),而多实现继承通常是(首选…)不赞成,而不是简单地使用组合。@dfrib:你能解释一下多重接口继承和多重实现继承的含义吗?@许多问题都说
a
是抽象的,假设
B:a
C:B
。如果你从未实例化
B
B
你不必重写
A
的虚拟函数。但是,如果你实例化
C
,你必须重写
A
的虚拟函数。这是一个完美的例子。干得好。我本来打算用
Draw()
做同样的回答。回答得好
struct Derived : public Abstract {
    void g() override {}  // #1
}

void h(Abstract const& obj) {
    obj.g();  // dynamic dispatch
}

int main() {
    Derived d{};
    h(d);  // Will result in invoke #1
}