8

我正在尝试从使用-fno-rtti 编译的共享库中进行子类化。不幸的是,我的代码库中的其他库需要 -frtti。结果,我收到链接错误,因为超类没有 typeinfo 结构。

在正常编译中收到错误:

out.o: in function typeinfo for MyClass:myclass.cpp(.data.rel.ro.<cpp magic>): error: undefined reference to 'typeinfo for NetlinkListener'

我想要子类化的类是 libsysutils 中的一个 android 类(剪掉一点空间):

class NetlinkListener : public SocketListener {
    char mBuffer[64 * 1024];
    int mFormat;

public:
    static const int NETLINK_FORMAT_ASCII = 0;
    static const int NETLINK_FORMAT_BINARY = 1;

    NetlinkListener(int socket);
    NetlinkListener(int socket, int format);
    virtual ~NetlinkListener() {}

protected:
    virtual bool onDataAvailable(SocketClient *cli);
    virtual void onEvent(NetlinkEvent *evt) = 0;
};

我的存根看起来像:

class MyClass: public NetlinkListener {

public:
    MyClass();
    virtual ~MyClass();

    int start();
    int stop();

protected:
    virtual void onEvent(NetlinkEvent *evt);
};

MyClass 中的所有方法都已实现(作为空存根)

我无法编译共享库 -frtti。有没有办法解决这个问题?

4

2 回答 2

5

1)对于简单的情况,您可以只创建接口的 C 包装器(不使用 RTTI 构建)。然后,您可以在启用 RTTI 的程序中使用 C 接口,前提是您将它​​们视为来自启用 RTTI 的程序的抽象 C 类型。

2)使用 RTTI 编译库正是您应该做的(或供应商的要求),除非有很好的理由禁用 RTTI(例如,您在不应使用异常的域中工作,例如作为内核、驱动程序或其他一些无异常区域——或者内存紧张的地方)。

3) 更改您的库以不使用 dynamic_cast、异常、typeid 运算符或任何导致问题的原因,并在禁用 RTTI 的情况下重建。与 1 类似,您可以将其设为单独的抽象库,具体取决于程序的组织方式。

4a) 下一个选项是永远不要引用对象的类型信息(例如,不要 dynamic_cast 或抛出它)——这可能会很痛苦。这将删除引用类型信息的链接器错误。

4b)创建内部类可能是最简单的(假设您必须覆盖某些方法,并且您必须与依赖于 rtti 的程序接口的类型)。您可以创建一个类型 ( inner),它从其 lib 的类型继承并执行必要的覆盖,然后通过其他一些类层次结构回调(其他层次结构可以自由使用 rtti)。现在inner该类的虚拟导出被放置在禁用rtti 的 TU 中(因为否则它将隐式引用其基类的类型信息)。然后,您可以轻松隔离类型信息依赖关系并构建一个使用异常之类的层次结构——该层次结构使用该inner类型作为值。当然,如果可行,则所有实现都已定义-- 您需要了解 RTTI 和 vtables 是如何为您的目标平台构建的(参见 ABI refs)。甚至省略 RTTI 也是与标准 C++ 的偏差。没有任何信息表明符号的存在会导致您的 vtables 的正确构造和在没有这些功能的情况下编译的基础的类型信息。

也就是说,1 和 2 是您的安全选项,3 在 no-rtti 平台扩展(安全)的范围内,4 是一种可以在没有或仅在某些系统上免费工作的方法。

说明 4b

class MyClass // << cast me. throw/catch me. get my mangled name,
              //    but put my family's virtual exports in a TU with RTTI enabled
: public MyRTTIEnabledFamily {
public:
    MyClass() : d_inner(*this) {}
    virtual ~MyClass();
private:
    void cb_onEvent(NetlinkEvent * evt) {
        // no-rtti suggests exceptions may not be available,
        // so you should be careful if your program throws.
        someInfo = evt->getInfo();
    }
private:
    // non-rtti hierarchy
    class t_inner : public NetlinkListener {
    public:
        t_inner(MyClass& pMyClass) : NetlinkListener(), d_myClass(pMyClass) {
        }

        virtual ~t_inner(); // << put your virtual exports in a TU with RTTI disabled.
                            //    one out of line virtual definition is necessary for most compilers
    private:
        virtual void onEvent(NetlinkEvent * evt) {
            // how the callback to your imp actually happens
            this->d_myClass.cb_onEvent(evt);
        }
    private:
        MyClass& d_myClass;
    };
private:
    t_inner d_inner; // << don't do anything with my type info -- it does not exist.
};
于 2013-03-05T00:30:53.113 回答
0

根据 gcc 的文档,传递-fno-rtti只会禁用dynamic_castand功能。typeid您应该能够毫无问题地派生类并使用虚拟方法。

undefined reference to typeinfo for class如果您将函数声明为virtual未为其提供定义,则通常会出现该错误。

事实上,我看到NetlinkHandler.h并且NetlinkHandler.cpp在 AOSP 中所做的正是您正在尝试做的事情,我发现这些文件与您发布的代码片段之间没有任何区别。

于 2013-03-05T00:32:14.027 回答