【问题标题】:Pure virtual function implementation纯虚函数实现
【发布时间】:2016-03-07 13:50:27
【问题描述】:

我正在阅读 Scott Meyers 的 Effective C++,我正在阅读关于继承的部分。他说

纯虚函数只指定接口的继承。

简单(不纯)虚函数指定接口的继承 加上默认实现的继承。

现在,考虑以下两个类:

struct A {
    virtual void foo() = 0;
};

void A::foo(){ std::cout << "Default foo" << std::endl; }

struct B : A{
    virtual void foo(){ A::foo(); std::cout << "Derived foo" << std::endl; }
};

我们仍然可以像我在示例中所做的那样为纯虚函数提供默认实现,并通过qualified-function-call-expression 调用它。对于不纯的虚函数,我们几乎可以做同样的事情

struct A {
    virtual void foo(); //No longer pure virtual
};

void A::foo(){ std::cout << "Default foo" << std::endl; }

struct B : A{
    virtual void foo(){ A::foo(); std::cout << "Derived foo" << std::endl; }
};

如果我不定义 impure 虚函数如下:

struct A {
    virtual void foo();
};



struct B : A{
    virtual void foo(){ std::cout << "Derived foo" << std::endl; }
};

它会工作得很好。

DEMO

那么,纯虚函数的唯一目的是使类抽象(不可实例化)?

【问题讨论】:

  • 选择所谓的默认实现还是需要派生类显式这样做的。
  • 如果您通过基类引用/指针调用foo,您的演示doesn't always work。使用 gcc 编译总是会导致链接器错误,而使用 clang 则取决于优化级别。
  • @stella,也不在不纯的虚函数中。如果派生类想要使用基类实现,它可以简单地不提供覆盖函数。这并不是说它可以隐式使用基类实现作为自己实现的part,而是选择默认实现,我的意思是整个实现。
  • “我们仍然可以像我在示例中所做的那样为纯虚函数提供默认实现,并通过...调用它” - 如果它是“默认实现”你不需要明确地调用它。它只是 一个 实现——C++ 方便地让您使用相同的函数名称,因此它可以向编写派生类的开发人员暗示它可能是他们自己的实现的有用支持函数,但它不会如果基类不能实现纯虚拟并且可能提供不同命名的支持函数,那么会有任何真正的不同。
  • 您的最后一个示例导致未定义的行为(无需诊断):由于A::foo() 未标记为= 0;,因此它必须在某处有一个主体(即使它从未被调用)。

标签: c++ inheritance definition virtual-functions one-definition-rule


【解决方案1】:

纯虚函数不仅使基类不可实例化,而且强制所有派生类实现相应的虚函数。如果您不将基函数设为纯虚拟,那么派生类可能会选择不实现它。定义纯虚函数是可以的,只要你从派生实例中使用它,并且它提供了一个可以作为默认使用的实现,正如 Scott Meyers 指出的那样。

请注意,您的演示并不像您想象的那样工作。如果您在使用多态性时执行通常被视为常见的操作,

A* p = new B; // or, std::unique_ptr<A> p = make_unique<B>();
p->foo();

然后你会得到一个讨厌的链接器错误:

架构 x86_64 的未定义符号:

"typeinfo for A",引用自: ccoVYpAI.o 中 B 的类型信息

【讨论】:

    猜你喜欢
    • 2016-02-18
    • 1970-01-01
    • 2021-10-26
    • 2013-12-31
    • 2011-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多