从 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()
).
你能解释一下为什么我可以在friend std::ostream& operator<<(...)
的实现中调用Base
class里面的纯虚函数吗?我认为这不应该是可能的。
您可以调用纯虚函数,因为当您调用它时,该函数不再是纯虚函数:派生的 class 必须覆盖它才能不再是 "abstract"。
编译器知道你不能自己实例化class Base
。这意味着您将无法在任何未为您的纯虚函数提供合适覆盖的 class 上调用 operator <<
。这就是编译器允许您进行调用的原因:它知道在运行时将有一个实现。
注意:调用纯虚函数的唯一方法是从基础 class 的构造函数中调用它。由于函数是纯虚函数,这会导致未定义的行为;现代编译器会警告您这个问题。
我不知道为什么下面的代码可以编译和工作(它工作得很好)。
#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()
).
你能解释一下为什么我可以在friend std::ostream& operator<<(...)
的实现中调用Base
class里面的纯虚函数吗?我认为这不应该是可能的。
您可以调用纯虚函数,因为当您调用它时,该函数不再是纯虚函数:派生的 class 必须覆盖它才能不再是 "abstract"。
编译器知道你不能自己实例化class Base
。这意味着您将无法在任何未为您的纯虚函数提供合适覆盖的 class 上调用 operator <<
。这就是编译器允许您进行调用的原因:它知道在运行时将有一个实现。
注意:调用纯虚函数的唯一方法是从基础 class 的构造函数中调用它。由于函数是纯虚函数,这会导致未定义的行为;现代编译器会警告您这个问题。