了解 C4673 编译器警告

Understanding C4673 compiler warning

有关警告的 MSDN 文章 C4673 包含此示例,该示例发出带有特定消息的警告:

Base: this base class is inaccessible
// C4673.cpp
// compile with: /EHsc /W4
class Base {
private:
   char * m_chr;
public:
   Base() {
      m_chr = 0;
   }

   ~Base() {
      if(m_chr)
         delete m_chr;
   }
};

class Derv : private Base {
public:
   Derv() {}
   ~Derv() {}
};

int main() {
   try {
      Derv D1;
      // delete previous line, uncomment the next line to resolve
      // Base D1;
      throw D1;   // C4673
   }

   catch(...) {}
}

不幸的是,MSDN 文章没有对这​​个问题给出任何解释。我不明白上面的代码有什么问题。为什么会发出警告?

这是 MSVC 2013 - v120 工具集。

我可以在 webcompiler 上重现这个警告的全文是:

main.cpp(28): warning C4673: throwing 'Derv' the following types will not be considered at the catch site
main.cpp(28): warning C4670: 'Base': this base class is inaccessible

没错。如果我们有:

try {
    throw Derv();
}
catch (Base& ) {
    std::cout << "I caught it!";
}

该处理程序不匹配 Derv 异常,因为 DervBase 私有继承,因此基 class 不可访问。所以在这个例子中,异常是未被捕获的。

但是,像 MSDN 示例中那样发出一个奇怪的警告,异常将被捕获:

catch(...) {}

所以看起来警告实际上并没有检查任何东西 - 它只是一个一般性的警告,你可能正在做一些有害的事情,而没有实际检查你是否这样做。这对我来说似乎不是特别有用的警告。如果我们在 Base& 之前赶上,是的 - 告诉我这不会发生 - 但我们在 ... 之前赶上。

这是一个更简化的例子:

class Base { public: virtual ~Base() {} };

class Derived : private Base {};

int main()
{
    Derived d;
    throw d;  // C4673
}

这里的问题是,开发人员可能会像这样编写一个 throw 语句作为任何函数的一部分,然后期望由此产生的异常被多态地捕获为 Base。这行不通,因为继承是 private。您必须赶上 Derived....

之所以在这里发出警告是合适的,是因为您不只是 throw 任何对象。通常,您有专门用于此目的的特定异常类型。对此类异常类型使用私有继承没有任何意义。它只会引入像这样令人困惑的行为,但没有真正的用例。

不幸的是,我们唯一可以检测到 class 是否为异常类型的地方是 throw,因此这是我们唯一可以生成此警告的地方。