2013-02-27 30 views
8

Tôi đang cố gắng phân lớp từ thư viện được chia sẻ với -fno-rtti. Thật không may các thư viện khác trong cơ sở mã của tôi yêu cầu -frtti. Kết quả là tôi nhận được các lỗi liên kết vì lớp cha không có cấu trúc typeinfo.Lớp phân lớp từ thư viện được chia sẻ được biên dịch với -fno-rtti

Lỗi nhận trong một bộ sưu tập bình thường:

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

Lớp tôi muốn phân lớp là một lớp android trong libsysutils (snipped một chút cho không gian):

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; 
}; 

còn sơ khai của tôi trông giống như:

class MyClass: public NetlinkListener { 

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

    int start(); 
    int stop(); 

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

Tất cả các phương pháp trong MyClass được thực hiện (dưới dạng phần trống)

Tôi không thể biên dịch thư viện được chia sẻ -frtti. Có cách nào để giải quyết vấn đề này không?

+0

Bạn có thể đăng một mã mẫu về cách bạn đang cố gắng phân lớp một siêu lớp không? – Tuxdude

+0

@Tuxdude Đã thêm tiêu đề. Không có triển khai thực hiện của lớp con (chỉ sơ khai). Mã cho siêu lớp là mã nguồn mở ASOP. –

Trả lời

4

1) Đối với các trường hợp đơn giản, bạn chỉ có thể tạo trình bao bọc C của giao diện (được xây dựng không có RTTI). Sau đó, bạn có thể sử dụng giao diện C trong các chương trình đã bật RTTI, với điều kiện bạn coi chúng là các loại C trừu tượng từ chương trình hỗ trợ RTTI của bạn.

2) Lập thư viện với RTTI là chính xác những gì bạn nên làm (hoặc theo yêu cầu của các nhà cung cấp), trừ khi có một lý do rất tốt cho RTTI bị vô hiệu (ví dụ bạn đang làm việc trong một miền nơi trường hợp ngoại lệ không nên được sử dụng, chẳng hạn như hạt nhân, trình điều khiển hoặc một số vùng không có ngoại lệ khác - hoặc nơi bộ nhớ bị chặt).

3) Thay đổi thư viện của bạn để không sử dụng dynamic_cast, ngoại lệ, toán tử typeid hoặc bất kỳ điều gì gây ra sự cố và xây dựng lại với RTTI bị vô hiệu hóa. Tương tự như 1, bạn có thể làm cho một thư viện trừu tượng riêng biệt này, tùy thuộc vào cách chương trình được tổ chức.

4a) Tùy chọn tiếp theo là không bao giờ tham khảo thông tin loại cho đối tượng (ví dụ: không dynamic_cast hoặc ném nó) - và điều này có thể là một nỗi đau. Điều đó sẽ loại bỏ lỗi trình liên kết của các loại infos được tham chiếu. Có thể dễ dàng nhất để tạo ra một lớp bên trong (giả sử có các phương pháp bạn phải ghi đè lên, và có các kiểu bạn phải giao tiếp với các chương trình phụ thuộc vào rtti của bạn). Bạn có thể tạo một loại (inner) kế thừa từ loại lib của chúng và thực hiện các ghi đè cần thiết, nhưng sau đó gọi lại thông qua một số phân cấp lớp khác (phân cấp khác là miễn phí để sử dụng rtti). Hiện tại, xuất khẩu ảo của lớp học inner được đặt trong TU với rtti bị vô hiệu hóa (vì nó sẽ ngầm tham chiếu đến thông tin loại của lớp cơ sở). Sau đó, bạn có thể dễ dàng kiểm dịch sự phụ thuộc vào loại thông tin và xây dựng một hệ thống phân cấp sử dụng những thứ như ngoại lệ - hệ thống phân cấp này sử dụng loại inner làm giá trị. Tất nhiên, nếu hoạt động, đó là tất cả triển khai được xác định - bạn sẽ cần phải hiểu RTTI và vtables được cấu trúc cho nền tảng được nhắm mục tiêu của bạn như thế nào (xem phần ABI refs). Thậm chí thiếu sót của RTTI là độ lệch so với chuẩn C++. Không có thông tin nào tuyên bố rằng sự hiện diện của một biểu tượng sẽ dẫn đến việc xây dựng đúng các vtables của bạn và loại thông tin của một cơ sở được biên dịch mà không có các tính năng đó.

Điều đó nói rằng, 1 và 2 là các tùy chọn an toàn của bạn, 3 nằm trong miền của phần mở rộng nền tảng no-rtti (an toàn) và 4 là phương pháp miễn phí để làm việc trên không hoặc chỉ một số hệ thống.

Minh họa 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. 
}; 
+0

Tôi đã xem xét giải pháp 1, nhưng vấn đề là có một phương thức 'virtual void onEvent (...)' mà lớp con của tôi cần ghi đè và sẽ được gọi bởi một phương thức được xác định superclass (onDataAvailable). Làm thế nào tôi có thể viết một wrapper, nhưng thành công trong việc nhận được cuộc gọi này trở lại? –

+0

Giải pháp 4b của bạn dường như đối phó với tình huống này. Bạn có thể cho tôi một số mã sơ khai về cách chính xác tôi sẽ thiết lập loại thừa kế này không? –

+0

@JonL đúng - bạn vẫn phải phân lớp phía sau giao diện C, sau đó bạn chỉ cần tạo một giao diện gọi lại cơ bản. dạng cơ bản của gọi lại cho máy khách là 'typedef void (* t_netlink_event_callback) (void * pContextInfo, NetlinkEvent * pEvent);' - vì vậy bạn gọi con trỏ hàm của ứng dụng khách trong ghi đè của bạn, sử dụng thông tin ngữ cảnh mà chúng đã truyền . ill.code: – justin

0

Đi qua -fno-rtti chỉ vô hiệu hóa các chức năng dynamic_casttypeid theo tài liệu hướng dẫn gcc của. Bạn sẽ có thể lấy được các lớp và sử dụng các phương thức ảo mà không có bất kỳ vấn đề nào.

Lỗi undefined reference to typeinfo for class thường xuất hiện nếu bạn khai báo hàm là virtual mà không cung cấp một defintion cho nó.

Thực tế tôi thấy NetlinkHandler.hNetlinkHandler.cpp trong AOSP thực hiện chính xác những gì bạn đang cố gắng làm và tôi không tìm thấy bất kỳ sự khác biệt nào giữa các tệp đó và đoạn mã bạn đã đăng.

+0

Mã của tôi cần biên dịch với '-frtti' vì một thư viện khác cần hàm' dynamic_cast'. Các AOSP NetlinkHandler trong vold (libvold) biên dịch '-fno-rtti' phù hợp với libsysutils, do đó, nó không có vấn đề này. –

Các vấn đề liên quan