我不确切知道为什么下面的代码会编译并运行(效果很好)。
#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;
}
我只在operator<<
类中定义Base
一次,它调用纯virtual display
函数。此方案通常用于避免在派生类中重写operator<<
,即在基类中只定义一次,然后使用另一个函数的虚拟调度(在我的例子中,display()
)。
你能解释为什么我能够在Base
的实现中调用friend std::ostream& operator<<(...)
类中的纯虚函数吗?我认为这不可能。
答案 0 :(得分:3)
你可以调用纯虚函数,因为当你调用它时,函数不再是纯虚函数:派生类必须覆盖它才能停止抽象&#34;抽象&#34;。
编译器知道你不能自己实例化类Base
。这意味着您无法在任何不为您的纯虚函数提供合适覆盖的类上调用operator <<
。这就是为什么编译器允许你进行调用:它知道在运行时会有一个实现。
注意:调用纯虚函数的唯一方法是从基类的构造函数中调用它。由于该函数是纯虚函数,因此会导致未定义的行为;现代编译器警告你这个问题。