199

我的基本理解是没有纯虚函数的实现,但是,有人告诉我可能有纯虚函数的实现。

class A {
public:
    virtual void f() = 0;
};

void A::f() {
    cout<<"Test"<<endl;
}

上面的代码可以吗?

使其成为具有实现的纯虚函数的目的是什么?

4

10 回答 10

236

virtual函数必须在将被直接实例化的派生类型中实现,但是基类型仍然可以定义实现。派生类可以通过使用全范围名称(通过A::f()在您的示例中调用 - if A::f()were publicor )显式调用基类实现(如果访问权限允许protected)。就像是:

class B : public A {

    virtual void f() {
        // class B doesn't have anything special to do for f()
        //  so we'll call A's

        // note that A's declaration of f() would have to be public 
        //  or protected to avoid a compile time problem

        A::f();
    }

};

我能想到的用例是当存在或多或少合理的默认行为时,但类设计者希望仅显式调用这种默认行为。也可能是您希望派生类始终执行自己的工作但也能够调用一组通用功能的情况。

请注意,即使语言允许它,它也不是我认为常用的东西(而且它可以完成的事实似乎让大多数 C++ 程序员,甚至是有经验的程序员都感到惊讶)。

于 2010-01-18T21:00:13.257 回答
85

需要明确的是,您误解了 what = 0; 后一个虚函数的意思。

= 0 表示派生类必须提供实现,而不是基类不能提供实现。

在实践中,当您将虚函数标记为纯 (=0) 时,提供定义几乎没有意义,因为它永远不会被调用,除非有人通过 Base::Function(...) 明确地这样做,或者如果基类构造函数调用有问题的虚函数。

于 2010-01-18T21:09:49.673 回答
20

如果您有应该由派生类执行的代码,但您不希望它直接执行 - 并且您希望强制它被覆盖。

您的代码是正确的,尽管总而言之,这不是一个经常使用的功能,并且通常仅在尝试定义纯虚拟析构函数时才会看到——在这种情况下,您必须提供一个实现。有趣的是,一旦你从那个类派生,你就不需要重写析构函数。

因此,纯虚函数的一个合理用法是将纯虚析构函数指定为“非最终”关键字。

下面的代码出奇地正确:

class Base {
public:
  virtual ~Base() = 0;
};

Base::~Base() {}

class Derived : public Base {};

int main() { 
  // Base b; -- compile error
  Derived d; 
}
于 2010-01-18T20:49:02.470 回答
20

它的优点是它强制派生类型仍然覆盖该方法,但还提供默认或附加实现。

于 2010-01-18T20:49:31.857 回答
7

例如,您必须将主体赋予纯虚拟析构函数:)

阅读:http ://cplusplus.co.il/2009/08/22/pure-virtual-destructor/

(链接断开,使用存档)

于 2010-01-18T21:24:23.180 回答
4

是的,这是正确的。在您的示例中,从 A 派生的类同时继承接口 f() 和默认实现。但是你强制派生类实现 f() 方法(即使它只是调用 A 提供的默认实现)。

Scott Meyers 在Effective C++ (2nd Edition) Item #36 中讨论了这一点,区分接口继承和实现继承。最新版本中的项目编号可能已更改。

于 2010-01-18T21:01:49.863 回答
4

有或没有主体的纯虚函数仅仅意味着派生类型必须提供它们自己的实现。

如果您的派生类想要调用您的基类实现,则基类中的纯虚函数体很有用。

于 2010-04-09T18:12:42.227 回答
3

'虚空 foo() =0;' 语法并不意味着你不能在当前类中实现 foo(),你可以。这也不意味着您必须在派生类中实现它。在你打我之前,让我们观察一下钻石问题:(隐式代码,请注意)。

class A
{
public: 
    virtual void foo()=0;
    virtual void bar();
}

class B : public virtual A
{
public:
    void foo() { bar(); }
}

class C : public virtual A
{
public:
    void bar();
}

class D : public B, public C
{}

int main(int argc, const char* argv[])
{
    A* obj = new D();
    **obj->foo();**
    return 0;
}

现在,obj->foo() 调用将导致 B::foo() 然后是 C::bar()。

你看... 纯虚方法不必在派生类中实现(foo() 在 C 类中没有实现 - 编译器会编译) 在 C++ 中有很多漏洞。

希望我能帮忙:-)

于 2015-03-24T20:55:57.020 回答
1

如果我问你什么是动物的声音,正确的回答是问哪个动物,这正是纯虚函数的目的,或者抽象函数是当你无法在基类(Animal)中为你的函数提供实现但每只动物都有自己的声音。

class Animal
{
   public:
       virtual void sound() = 0;
}

class Dog : public Animal
{
   public:
       void sound()
       {
           std::cout << "Meo Meo";
       }
}
于 2021-11-27T22:32:09.080 回答
0

拥有带有实现主体的纯虚拟方法的一个重要用例是,当您想要拥有一个抽象类,但您在该类中没有任何适当的方法使其成为纯虚拟时。在这种情况下,您可以将类的析构函数设为纯虚拟并为此放置所需的实现(甚至是空的主体)。举个例子:

class Foo
{
   virtual ~Foo() = 0;
   void bar1() {}
   void bar2(int x) {}
   // other methods
};

Foo::~Foo()
{
}

这种技术使Foo类抽象化,因此无法直接实例化该类。同时,您还没有添加额外的纯虚方法来使Foo类抽象。

于 2020-04-29T08:27:22.057 回答