本文中的類反射指的是例項的型別識別(rtti)、動態建立,繼承鏈遍歷能力,不討論成員函式、成員變數等的反射。即實現以下類似介面:
classfoo :
public
object
;object
*obj1
=new
foo();
iskindof(obj1,
"foo
");
//型別識別
object
*obj2
=createobject(
"foo
");
//動態建立
getbaseclass(obj1) =="
object
"
本小節實現類反射的三大能力:例項型別識別、動態建立和繼承鏈遍歷。為了類繼承結構的組織方便,實現了類反射的類通常會有乙個公共基類,例如在mfc中就是cobject。我們定義乙個公共基類:
classobject
};
首先實現例項型別識別,例項型別識別可以考慮使用typeid(instance).name()來實現,但是需要該類具有虛函式表,並且返回值也是編譯器相關的,而不是真正的類名。我們在每個類中新增乙個靜態成員變數來儲存類資訊,並定義乙個虛函式時每個例項可以正確獲取到類資訊。為了實現方便,這裡定義乙個classinfo類來表示類資訊:
classclassinfo
const
std::
string
&getclassname()
const
bool
iskindof(
const
std::
string
&classname)
const
private
: std::
string
m_classname;
};
在每個類中新增乙個靜態成員變數和虛函式:
//.hclass
foo :
public
object
static
classinfo ms_classinfo;
};//
.cpp
classinfo foo::ms_classinfo(
"foo");
這樣我們就簡單地實現了例項型別識別,可以做如下測試:
object*obj
=new
foo();
assert(obj
->
getclasinfo()
->
iskindof(
"foo
"));
然後實現動態建立能力,先定義介面,新增了成員函式findclass(靜態)和createobject:
classinfo*fooinfo
=classinfo::findclass(
"foo");
assert(fooinfo);
object
*obj
=fooinfo
->
createobject();
定義乙個hash單例,儲存類名到classinfo的對映,findclass使用該hash表查詢。classinfo並不知道如何建立例項,需要我們在每個類中新增createobject,然後傳遞給classinfo。
+typedef object*(
*objectconstructor)(
void);
class
classinfo
const
std::
string
&getclassname()
const
bool
iskindof(
const
std::
string
&classname)
const
+object
*createobject()
const+
+static
classinfo
*findclass(
const
std::
string
&classname)+
private:+
void
register()+
std::
string
m_classname;
+objectconstructor m_objectctor;
}; //.h
class
foo :
public
object +
static
object
*createobject()+
static
classinfo ms_classinfo;
};//
.cpp
classinfo foo::ms_classinfo(
"foo
", (objectconstructor)(foo::createobject));
最後,在classinfo中加入繼承鏈遍歷(為了簡化問題,只考慮單繼承):
class
classinfo +
const
classinfo
*getbaseclass()
const+
private: +
const
classinfo
*m_baseinfo;
...}; //
.cpp
classinfo foo::ms_classinfo(
"foo",
(objectconstructor)(foo::createobject),+&
object::ms_classinfo);
現在我們已經實現了所有的功能,也可以繼續給classinfo新增一些有用的介面,例如iskindof等。但是,實際使用時每個類都要手動寫這麼多**是很麻煩的,使用巨集可以幫我們簡化:
typedef object*(*objectconstructor)(
void
);#define
declare_class(name) \
public
: \
static
classinfo ms_classinfo; \
virtual
classinfo
*getclassinfo()
const
; \
static
object
*createobject()
#define
implement_class(name, basename) \
classinfo name::ms_classinfo(#name, \
(objectconstructor)(name::createobject), \
&basename::ms_classinfo) \
classinfo
*name::getclassinfo()
const
\ \
object
*name::createobject() \
//.h
class
foo :
public
object;//
.cpp
implement_class(foo, object)
本文只是為了闡述思路,實際使用時還需要根據類的特徵來定製不同的巨集(是否支援動態建立,多基類支援等)。
上文中實現的類反射需要所有的類擁有乙個共同基類,但是有時候乙個工程中可能需要使用多套類繼承體系,這時又需要重寫一套反射類和巨集。我們可以使用模板定製乙個更靈活的類反射系統。類資訊classinfo需要加乙個模板引數作為該組的共同基類:
template<
class
_groupbase
>
class
classinfo
;
具體實現不再贅述,附上**:
link
C 多繼承與虛基類
多繼承的定義 派生類的基類大於乙個 語法 class 派生類名 繼承方式1 基類名1,繼承方式2 基類名2.多重繼承與建構函式的關係 多重繼承時建構函式的作用 1 初始化派生類 自己 2 呼叫該派生類所有基類建構函式,並且為所有基類傳參 引數個數必須包含所有基類所需引數 建構函式語法 派生類建構函式...
C 虛基類的實現機制
在 深度探索c 物件模型 裡,有乙個問題,也是去公司面試的時候那些技術人員常問的問題 在c 中,obj是乙個類的物件,p是指向obj的指標,該類裡面有個資料成員mem,請問obj.mem和p mem在實現和效率上有什麼不同。答案是 只有一種情況下才有重大差異,該情況必須滿足以下3個條件 1 obj ...
C 排序演算法 基類的實現
論壇中經常有人問選擇法 冒泡法排序演算法用c 怎麼實現,正好我手頭上有這方面的 乾脆拿出來跟大家分享一下。其實 已經寫了很久了,只是平時工作比較忙,沒時間整理。現在失業了,每天呆在家裡實在無聊,就抽空把這部分 整理出來。好了,廢話少說,進入正題吧。排序演算法,首先應該考慮的是通用性,不管是陣列,還是...