C ++ / Linux:对typeinfo的未定义引用,但虚拟方法似乎没问题

时间:2013-01-31 20:46:06

标签: c++ linux exception g++

我的项目中有所有异常的基类。它是这样实现的:

Exception.hpp

class Exception : public std::exception
{
public:

    ELS_EXPORT_SYMBOL Exception(void) throw();
    ELS_EXPORT_SYMBOL explicit Exception(const std::string& what) throw();
    ELS_EXPORT_SYMBOL Exception(const char* format, ...) throw()
            ELS_PRINTF_FUNC(2, 3);
    ELS_EXPORT_SYMBOL Exception(const Exception& other) throw();
    ELS_EXPORT_SYMBOL Exception& operator =(const Exception& other)
            throw();
    ELS_EXPORT_SYMBOL virtual ~Exception(void) throw();

    ELS_EXPORT_SYMBOL virtual const char* what(void) const throw();

protected:

    ELS_EXPORT_SYMBOL void _M_setWhat(const char* format, ::va_list va)
        throw();

private:

    std::string _M_what;
};

#define ELS_EXC_VA_SET_WHAT(FORMAT)                                         \
    do                                                                      \
    {                                                                       \
        ::va_list va;                                                       \
        ::va_start(va, FORMAT);                                             \
        this->_M_setWhat(FORMAT, va);                                       \
        ::va_end(va);                                                       \
    }                                                                       \
    while (false)

Exception.cpp

Exception::Exception(void) throw()
    : std::exception(),
      _M_what("Exception")
{

}

Exception::Exception(const std::string& what) throw()
    : std::exception(),
      _M_what(what.empty() ? "Exception" : what)
{

}

Exception::Exception(const char* format, ...) throw()
    : std::exception(),
      _M_what()
{
    ELS_EXC_VA_SET_WHAT(format);
}

Exception::Exception(const Exception& other) throw()
    : std::exception(other),
      _M_what(other._M_what)
{

}

Exception& Exception::operator =(const Exception& other) throw()
{
    std::exception::operator =(other);
    this->_M_what = other._M_what;
    return *this;
}

Exception::~Exception(void) throw()
{

}

const char* Exception::what(void) const throw()
{
    return this->_M_what.c_str();
}

void Exception::_M_setWhat(const char* format, ::va_list va) throw()
{
    static const size_t BUFSIZE = 512;

    char buf[BUFSIZE];

    ::memset(buf, 0, BUFSIZE);
    ::vsnprintf(buf, BUFSIZE, format, va);
    this->_M_what = std::string(buf);
}

这些文件是使用以下选项编译的共享库的一部分:

-Wall -fPIC -O2 -D_GNU_SOURCE -fvisibility=hidden -rdynamic -Wl,-E

库本身编译没有任何问题,但是当我尝试编译二进制文件并将其链接到它时,我收到以下错误:

Main.cpp:(.text+0x297): undefined reference to `typeinfo for els::except::Exception'

我用谷歌搜索了一下,常见的答案是要么实现所有的虚拟方法,要么让它们变得纯净。我在这里没有看到这个问题。我做错了什么?

3 个答案:

答案 0 :(得分:1)

好的,我得到了这个 - 我必须使整个班级可见 - 类ELS_EXPORT_SYMBOL异常。

答案 1 :(得分:0)

  

图书馆本身编译没有任何问题,但是当我尝试和   编译二进制文件并将其链接到它我得到以下错误

什么是链接命令行?

您可能认为您过早地传入了库,因此链接器在它需要该定义之前已经处理过它。

答案 2 :(得分:0)

当.so文件与C ++标准库静态链接时,Linux上存在RTTI问题。在一个.so中实例化的类在另一个.so中不可用于内省,因为它们具有不同的RTTI表(因为每个.so都有自己的C ++运行时副本,因为静态链接)。

您有两种选择: 1.在所有程序部分上使用与C ++运行时的动态链接(我使用此选项) 2.明确地暴露类,就像你已经想到的那样(当你有很多课时会变得烦人)