簡體   English   中英

自動化LLVM樣式的RTTI代碼

[英]Automate LLVM style RTTI code

對於特定的類層次結構,我需要知道基類引用是否是特定派生類的實例。 由於不同的原因,我不能在這里使用標准的C ++ RTTI,我需要實現自定義的instanceof機制。

LLVM-stle RTTI可滿足我的需求,但我想知道它是否存在(以某種方式使用模板)自動化classof方法的實現?

是否有其他/更簡單的實現這種機制,可以知道基類是否是派生類的實例?

我的約束:

  • 我沒有多重繼承,但我有幾個級別的繼承。
  • 對內存占用的影響必須盡可能小,並且無法執行動態分配。

我想知道它是否存在一種方式(以某種方式使用模板)來自動化classof方法的實現?

是的,有一些方法可以自動化classof方法,我真的不明白為什么LLVM頁面會演示一組手動的類方法,因為如果你自動化這個非常簡單的過程它會更具可伸縮性。

這是一個非常基本的解決方案:

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

    virtual int getClassId() const { return 0; };
    static int getStaticClassId() { return 0; };

    virtual bool isOfType(int aID) const { return (aID == 0); };

    template <typename T>
    bool isOfClass() const { return isOfType( T::getStaticClassId() ); };

};

運行時強制轉換(即dynamic_cast )函數如下所示:

template <typename T>
T* runtime_ptr_cast(TypedObject* p) {
  if( (p) && (p->isOfClass<T>()) )
    return static_cast<T*>( p );
  return NULL;
};

template <typename T>
typename std::enable_if< 
  std::is_const< T >::value,
T* >::type runtime_ptr_cast(const TypedObject* p) {
  if( (p) && (p->isOfClass<T>()) )
    return static_cast<T*>( p );
  return NULL;
};

那么,你需要的只是MACRO來自動創建虛擬和靜態函數:

#define MY_RTTI_SYSTEM_CREATE_TYPE_1_BASE( NEWCLASSID, BASECLASSNAME ) \
  public: \
    virtual int getClassId() const { return NEWCLASSID; }; \
    static int getStaticClassId() { return NEWCLASSID; }; \
     \
    virtual bool isOfType(int aID) const { \
      return ((aID == NEWCLASSID) || BASECLASSNAME::isOfType(aID)); \ 
    };

然后,您可以創建一個這樣的新類:

class Foo : public TypedObject {

  // ... some code, as usual ...

  // call the macro with a given ID number and the name of the base-class:
  MY_RTTI_SYSTEM_CREATE_TYPE_1_BASE(1, TypedObject)
};

這導致:

int main() {
  Foo f;
  TypedObject* b = &f;

  // check the type:
  if( b->isOfClass<Foo>() ) 
    std::cout << "b is indeed for class Foo!" << std::endl;

  // make a dynamic cast:
  Foo* pf = runtime_ptr_cast<Foo>( b );
  if( pf )
    std::cout << "cast to 'Foo*' was successful!" << std::endl;

  const TypedObject* cb = b; 
  const Foo* cpf = runtime_ptr_cast<const Foo>( cb );
  if( cpf )
    std::cout << "cast to 'const Foo*' was successful!" << std::endl;

  Foo* pf2 = runtime_ptr_cast<Foo>( cb ); // ERROR: no such function (invalid cast).
};

當然,您也可以通過創建更多MACRO來注冊類型來將其擴展為多重繼承。 這個方案也有無數的變化(個人而言,在我的實現中 ,我將類型注冊到全局存儲庫並且也可以訪問工廠函數)。

我認為沒有任何實際的方法可以避免在您創建的每個類中使用MACRO調用。 我已經考慮了一段時間(前段時間,因為我自己制作)並且我得出結論,最簡單和最干凈的解決方案是在課堂上進行MACRO調用(盡管我對MACROs有很大的蔑視)一般)。 但我不知道,也許其他人有一個更好的(基於模板的)解決方案,這不會導致太多的混亂或不是太介入。 我已經使用這個計划多年了,它非常干凈整潔。

我沒有多重繼承,但我有幾個級別的繼承。

上述方案適用於任何繼承級別(即,它是可擴展的解決方案)。 如果有一天你想這樣做,它也可以很容易地適應多重繼承。

對內存占用的影響必須盡可能小

我知道LLVM更喜歡沒有任何虛函數的解決方案,而是在基類中使用整數id數據成員。 使用這種方案實現與上述相同類型的功能變得有點困難(但可能)。 使用虛函數要容易得多,虛函數只占用一個指針(vtable指針)的空間,這通常不比整數id數據成員大。 如果類已經是多態的,那么成本就沒有了。 當然,上面的內容比內置的C ++ RTTI輕得多。 所以,除非你真的想用一個整數id(或枚舉)解決方案來擠出那些你可以備用的字節,我建議你選擇一個基於虛函數的解決方案,就像我上面所說的那樣。

無法執行動態分配。

通常不需要動態分配。 只有更復雜(和功能豐富)的RTTI實現才需要一些動態分配。 如果你想要的只是能夠做“classof()”(因此,動態轉換),那么肯定不需要動態內存分配。

您希望某種樹(如數據結構)作為全局變量來存儲您的類層次結構

class Foo : public Foo_Parent {
  IS_PART_OF_HIERARCHY

public:
  Foo();
  ...
}

#define IS_PART_OF_HIERARCHY
  private:
    static Hierarchy<string> *node;
  public:
    bool isChildOf( string parent ) const;
    bool isParentOf( string child ) const;

在.cpp文件中

INSERT_INTO_HIERARCHY( Foo, Foo_Parent )

Foo::Foo() {}
....

#define INSERT_INTO_HIERARCHY( class_name, parent_class_name )
  Hierarchy<string> class_name::node = classes_hierarchy.insertAfter( #parent_class_name );
  bool class_name::isChildOf const( string ) {
      auto *node = class_name::node;
      // traverse the parents of node
  }
  bool class_name::isParentOf const( string ) {
      auto *node = class_name::node;
      // traverse the children of node
  }

我在STL中找不到層次結構類,實現一個層次結構很難,我不知道是否值得付出努力。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM