我想知道它是否會存在方式(以某種方式使用模板)來自動classof方法的實現?
是的,有辦法來自動classof方法,我真的不明白,爲什麼LLVM頁面將證明手卷組classof方法,因爲它是如此更可擴展,如果你自動執行非常簡單的過程。
這裏是一個非常基本的解決方案:
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;
};
然後,所有你需要的是宏自動化創建虛擬和靜態功能:
#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)); \
};
然後,你可以創建E中的新類這樣的:
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).
};
和當然,你可以只創建註冊類型的多個宏擴展,以多重繼承也。這個方案也有無數的變化(個人,my implementation,我註冊到全球存儲庫的類型,並允許訪問工廠功能)。
我不認爲有任何實際的方法可以避免在您創建的每個類中使用MACRO調用。我已經考慮了一段時間(前一段時間,因爲我是自己做的),並且我得出結論:最簡單和最乾淨的解決方案是在課堂上進行MACRO調用(即使我非常鄙視MACRO一般)。但我不知道,也許其他人有一個更好的(基於模板的)解決方案,不會造成太多混亂或不太侵擾。我一直在使用這個方案多年,而且它非常乾淨。
我沒有多繼承,但我有幾個級別的繼承。
上述方案適用於任何級別的繼承(即它是可擴展的解決方案)。如果有一天你想這樣做,它也可以很容易地適應多重繼承。我知道LLVM傾向於沒有任何虛擬函數的溶液,並使用而不是在基類的完全一體的id數據構件上的內存佔用
影響必須儘可能
爲最小。用這種方案實現與上述相同的功能變得有點困難(但可能)。使用虛擬函數要容易得多,它只佔用一個指針(vtable指針)的空間,這個指針通常不會比整數id數據成員大得多。如果課程已經是多態的,那麼成本根本不算什麼。而且,當然,上述內容比內置的C++ RTTI輕得多。因此,除非你真的想要用積分id(或enum)解決方案來擠壓那些可以節省的字節,否則我會建議你使用基於虛擬功能的解決方案,就像我上面展示的那樣。
無法執行動態分配。
一般不需要動態分配。只有更復雜(功能豐富)的RTTI實現需要一些動態分配。如果你只想做「classof()」(因此是動態強制轉換),肯定不需要動態內存分配。
如何添加像'get_class_id()'這樣的虛函數? – 2013-04-04 14:58:50
@KerrekSB基本上LLVM風格的RTTI是如何工作的。每個類都有一個靜態標識符。問題不在於如何唯一標識一個班級。 – greydet 2013-04-04 15:04:46