通过将前向声明替换为 include 来更改代码的含义

Change the meaning of code by replacement of forward declaration with include

Google C++ Style Guide 表示

In extreme cases, replacing an #include with a forward declaration can silently change the meaning of code.

你能帮我找一些例子吗?

这里有两种情况。其中之一是 UB,另一个我认为是定义的行为变化(假设没有 ODR 或类似的违规行为:即,没有调用 foo 会看到 A 的定义,但我不确定)

namespace N {
  struct B {};
  struct A;//:B{};
}

void foo(N::B*){
  std::cout << "B\n";
}
template<class T, class=std::enable_if_t<!std::is_convertible<T*,N::B*>{}>>
void foo(T*){
  std::cout << "T\n";
}

int main() {
  foo( (N::A*)0 );
}

struct A; 替换为 struct A:B{}; 将更改调用哪些 foo 重载。

此外,如果 delete A; 被调用时 delete A; 是可见的,那么 delete A; 将调用 ~A()。否则,如果存在非平凡的析构函数,我们就有 UB。在这种情况下,代码的含义发生了变化,它从 UB 变为 DB,我想这是一个含义的变化。

我所知道的最阴险的例子之一是 C 风格的转换与继承相结合。

假设你有:

class Parent1 {};
class Parent2 {};

class Child : public Parent1, public Parent2 {};

然后在其他文件中您从 Parent2 投射到子文件:

Parent2* parent2_ptr = new Child;
Child* obj = (Child*)parent2_ptr;

根据完整定义,C 风格转换是 static_cast,正确地修复了地址。通过(Child 的)前向声明,C 风格转换成为 reinterpret_cast 无声地破坏代码。