重新声明纯虚函数

Seb*_*ann 4 c++

我最近遇到了以下类型的代码:

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

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

struct C : public B {
    virtual void foo() override {
    }
};
Run Code Online (Sandbox Code Playgroud)

重新声明纯虚方法有什么目的吗?

更重要的是:这会改变语义吗?即B::foo隐藏A::foo并引入新的 vftable?

如果A::foo实际上不是纯虚拟但提供了一个实现(仍然为我编译),那么在上面的示例中会发生什么?

for*_*818 7

查看cppreference中的示例 :

struct Abstract {
    virtual void f() = 0; // pure virtual
}; // "Abstract" is abstract
 
struct Concrete : Abstract {
    void f() override {} // non-pure virtual
    virtual void g();     // non-pure virtual
}; // "Concrete" is non-abstract
 
struct Abstract2 : Concrete {
    void g() override = 0; // pure virtual overrider
}; // "Abstract2" is abstract
 
int main()
{
    // Abstract a; // Error: abstract class
    Concrete b; // OK
    Abstract& a = b; // OK to reference abstract base
    a.f(); // virtual dispatch to Concrete::f()
    // Abstract2 a2; // Error: abstract class (final overrider of g() is pure)
}
Run Code Online (Sandbox Code Playgroud)

重新声明纯虚方法有什么目的吗?

在派生类Abstract2中将虚方法声明为纯方法是有目的的:g即使在Concrete.

这会改变语义吗?即 B::foo 隐藏 A::foo 并引入新的 vftable 吗?

不。

如果 A::foo 实际上不是纯虚拟的但提供了一个实现(仍然为我编译),那么在上面的例子中会发生什么?

请参阅示例。

您不必像virtual在派生类中那样对方法进行 delcare 。当它virtual在基virtual类中声明时,它也在派生类中。简而言之, the=0只是告诉编译器不一定有定义,并且该类是抽象的。您的示例与以下示例相同:

struct AA {                       // abstract
    virtual void foo() = 0;         
};

struct BB : public AA { };         // abstract

struct CC : public BB {            // concrete
    void foo() override {}
};
Run Code Online (Sandbox Code Playgroud)

我知道的唯一区别是类型BB::foo

// above
std::cout << std::is_same< decltype(&BB::foo), void (AA::*)()>::value;
std::cout << std::is_same< decltype(&BB::foo), void (BB::*)()>::value;
std::cout << std::is_same< decltype(&BB::foo), void (CC::*)()>::value << "\n";
// your example
std::cout << std::is_same< decltype(&B::foo), void (A::*)()>::value;
std::cout << std::is_same< decltype(&B::foo), void (B::*)()>::value;
std::cout << std::is_same< decltype(&B::foo), void (C::*)()>::value << "\n";
Run Code Online (Sandbox Code Playgroud)

输出是:

100
010
Run Code Online (Sandbox Code Playgroud)

也就是说,重新声明fooB名称介绍foo直接BB::foo是 的成员函数B。另一方面,在我的示例中BB::foo是来自AA. 但是,这并不影响C::foo.