从 operator<< 调用纯虚函数

calling a pure virtual function from operator<<

我不知道为什么下面的代码可以编译和工作(它工作得很好)。

#include <iostream>

struct Base
{
    virtual std::ostream& display(std::ostream& os) const = 0;
    friend std::ostream& operator<<(std::ostream& lhs, const Base& rhs)
    {
        return rhs.display(lhs);
    }
};

struct A: Base
{
    virtual std::ostream& display(std::ostream& os) const
    {
        return os << "A" << std::endl;
    }
};

struct B: A
{
    virtual std::ostream& display(std::ostream& os) const
    {
        return os << "B" << std::endl;
    }
};

int main()
{
    A a;
    std::cout << a << std::endl;

    B b;
    std::cout << b << std::endl;
}

我只在 Base class 中定义了一次 operator<<,它调用了纯 virtual display 函数。该方案通常用于避免在派生的 class 中重写 operator<<,即在基础 class 中仅定义一次,然后将虚拟调度与另一个函数一起使用(在我的例子中, display()).

Live on Coliru

你能解释一下为什么我可以在friend std::ostream& operator<<(...)的实现中调用Baseclass里面的纯虚函数吗?我认为这不应该是可能的。

您可以调用纯虚函数,因为当您调用它时,该函数不再是纯虚函数:派生的 class 必须覆盖它才能不再是 "abstract"。

编译器知道你不能自己实例化class Base。这意味着您将无法在任何未为您的纯虚函数提供合适覆盖的 class 上调用 operator <<。这就是编译器允许您进行调用的原因:它知道在运行时将有一个实现。

注意:调用纯虚函数的唯一方法是从基础 class 的构造函数中调用它。由于函数是纯虚函数,这会导致未定义的行为;现代编译器会警告您这个问题。