如何导出继承自std::runtime_error的类?

17

我已经建立了一个提供从标准异常派生出的异常类的库:

#include <stdexcept>
#include <string>

class BaseException : public std::runtime_error
{
    public:
        BaseException( std::string const & msg );
};

到目前为止,一切都很顺利,在Unix上编译和处理得相当不错。现在我正在准备将其编译成Windows DLL:

#ifdef WIN32
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT
#endif

#include <stdexcept>
#include <string>

class MY_EXPORT BaseException : public std::runtime_error
{
    public:
        BaseException( std::string const & msg );
};

然而,这给了我一个警告C4275non – DLL-interface class 'std::runtime_error' used as base for DLL-interface class 'BaseException'

很不幸,我有点对微软风格的文档产生过敏反应:太啰嗦了,也没有明确的指示。这让我完全搞不清楚需要做什么来解决我的问题。

你们中的任何人都能启发我吗?我可以放弃基类,但是那样捕获std::runtime_errorstd::exception就无法捕获我的自定义异常类了,而我非常希望能够实现这一点。所以,怎么办?

1个回答

18
在这种情况下,您有几个选项。
  1. 导出它。
  2. 忽略它。
  3. 内联它。
需要记住的是,从dll中导出类的“正确”方式是导出整个类,包括基类和成员。因此,有一些技术,例如CodeProject上的这个,使用“接口”和适当的工厂来创建类(和匹配销毁)。
在这种情况下,这对您不太有用,尝试导出 std::runtime_error 可能需要更多的努力,并且很可能会在以后引入更大的问题。
Microsoft Connect网站webarchive)中获取,这些错误的家族本质上是噪音;
我建议首先避免这种情况 - 在DLL接口中放置STL类型会强制您按照STL的规则进行操作(特别是,您不能混合使用不同版本的VC,并且您的IDL设置必须匹配)。但是,有一个解决方法。 C4251本质上是噪音,可以消除它...
Stephan T. Lavavej(Micrsoft的C ++库维护者之一)。
只要编译器选项在整个项目中保持一致,静默此警告应该就可以了。
最后的选择是内联定义BaseException类并根本不导出它。
根据我的经验,内联选项几乎总是异常类最容易的选择。

VS2015中C++运行时的变化导致了对std::exception的导出方式的更改(它不再从运行时中导出)。

此时,内联选项似乎是最合适的选择(可能因情况而异)。

class Exception : exception {
public:
    char const* what() const override;
};

inline char const* Exception::what() const {
    /*...*/
};

1
@DevSolar 其实,你只需注意不改变与标准库(如迭代器调试等)相关的编译器选项和宏定义,那么就应该没问题了。 - Niall
1
确实如此,而std::runtime_error则不是。感谢微软搞砸了这个问题。我更喜欢从std::runtime_error派生,因为它具有char const *构造函数,而std::exception缺少该构造函数,这使得事情变得*更加容易。我知道我为什么喜欢避免在Windows上编码... - DevSolar
1
Microsoft Connect链接会跳转到登录页面,而不是有用的内容。 - Sqeaky
1
@sqeaky。我会尝试找到一个公开可见的版本,如果您有live.com或outlook.com等帐户,可以使用该帐户。关键部分是答案中引用的部分。请勿考虑VS2015中更改的上面的评论。 - Niall
1
@Sqeaky。看起来原始问题已被删除,它是针对VS2010的,所以我并不感到惊讶。我找到了一个WebArchive链接,并将其添加。 - Niall
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接