C++ Builder 參考手冊 ? C++ Builder 的反射 (二) - Reflection Factory
上一篇文章 C++ Builder 的反射 (Reflection) (一) 介紹了從 TObject 繼承的類的反射方法,這篇文章繼續(xù)論述從 TObject 繼承的類的反射,根據(jù)上一篇文章,做一個通用的類模板,這個類模板需要 C++ 11 / clang 編譯器来屠。本文的程序和例子已經(jīng)用 C++ Builder 10.2.3 版本 clang 32位 和 clang 64位編譯器測試通過。
- Reflection Factory 類模板
- 測試控件的反射
- 測試自己寫的類的反射
1. Reflection Factory 類模板
THsuanluReflectionFactory 類模板的參數(shù):
- TBaseClass 為可以反射的類的公共父類,通過類名字符串反射創(chuàng)建的類通過這個類型的指針返回馍驯;
- TConstructorParams 為反射的類的構(gòu)造函數(shù)的參數(shù)的類型阁危,這不是單一的參數(shù),而是一組隨意個數(shù)和類型的參數(shù)汰瘫,也可以沒有狂打。由于創(chuàng)建類的時候,必需調(diào)用類的構(gòu)造函數(shù)吟吝,所以需要提供類的構(gòu)造函數(shù)的每個參數(shù)的類型菱父,請參考 C++ 可變參數(shù)的模板,構(gòu)造函數(shù)參數(shù)相同的類剑逃,可以注冊到這個 Reflection Factory 里面浙宜;
Register 方法為注冊需要反射的類,模板參數(shù) TClassType 為要注冊的類蛹磺;
Create 方法為通過類名字符串創(chuàng)建類粟瞬,參數(shù) sClassName 為類名字符串,參數(shù) Params 為構(gòu)造函數(shù)的可變參數(shù)萤捆,通過 new TClassType(Params...) 創(chuàng)建注冊的類裙品。
#include <map>
template <class TBaseClass, class... TConstructorParams> // 公共父類, 構(gòu)造函數(shù)參數(shù)類型
class THsuanluReflectionFactory
{
private:
std::map<UnicodeString, TBaseClass*(*)(TConstructorParams...)>_ClassMap;
public:
template<class TClassType> // 要注冊的類
void Register(void) // 注冊 TClassType 類
{
_ClassMap[TClassType::ClassName()] = [](TConstructorParams... Params) -> TBaseClass*
{
return new TClassType(Params...);
};
}
TBaseClass *Create(UnicodeString sClassName, TConstructorParams... Params)
{
auto iter = _ClassMap.find(sClassName);
if(iter == _ClassMap.end())
throw Exception(L"類 \"" + sClassName + L"\" 未注冊");
return iter->second(Params...);
}
};
2. 測試控件的反射
- 這個例子在程序開始運行時,即在主窗口的構(gòu)造函數(shù)里面俗或,注冊了 TLabel市怎、TButton、TMemo辛慰、TEdit区匠、TCheckBox、TRadioButton帅腌、TComboBox 等幾個控件類驰弄,可以使用他們的類名字符串來創(chuàng)建控件對象。
- 由于控件類的構(gòu)造函數(shù)都有一個 TComponent* Owner 參數(shù)速客,在定義 ControlsFactory 的時候戚篙,模板參數(shù)除了公共父類 TControl 之外,還有一個 TComponent* 參數(shù)溺职。
THsuanluReflectionFactory<TControl, TComponent*> ControlsFactory;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
ControlsFactory.Register<TLabel>();
ControlsFactory.Register<TButton>();
ControlsFactory.Register<TMemo>();
ControlsFactory.Register<TEdit>();
ControlsFactory.Register<TCheckBox>();
ControlsFactory.Register<TRadioButton>();
ControlsFactory.Register<TComboBox>();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ButtonCreateClick(TObject *Sender)
{
try
{
TControl *p = ControlsFactory.Create(EditClassName->Text, this);
p->Parent = this;
p->SetBounds(EditLeft->Text.ToIntDef(0), EditTop->Text.ToIntDef(0), EditWidth->Text.ToIntDef(80), EditHeight->Text.ToIntDef(30));
}
catch(Exception &e)
{
ShowMessage(e.Message);
}
}
編輯框 EditClassName 輸入控件的類名岔擂,
編輯框 EditLeft, EditTop, EditWidth, EditHeight 分別用于輸入控件的位置和大小,
按鈕 ButtonCreate 創(chuàng)建控件浪耘,ButtonCreateClick 方法就是點擊這個按鈕執(zhí)行的代碼智亮。
運行結(jié)果:
創(chuàng)建一個 TComboBox:
再創(chuàng)建一個 TCheckBox 和一個 TRadioButton
3. 測試自己寫的類的反射
由于本文討論從 TObject 繼承的類的反射,這里寫幾個類:其中 THsuanluBase 從 TObject 繼承点待,作為其他幾個類的公共父類阔蛉,反射的結(jié)果是通過這個類型的指針返回通過類名字符串創(chuàng)建的對象。要注意:通過父類指針訪問子類的方法要定義為虛函數(shù)癞埠。
class THsuanluBase : public TObject
{
public:
virtual void PrintMessage(void){ Form1->Memo1->Lines->Add(L"這是父類的 PrintMessage 方法"); }
};
//---------------------------------------------------------------------------
class THsuanluTest1 : public THsuanluBase
{
public:
virtual void PrintMessage(void){ Form1->Memo1->Lines->Add(L"這是 THsuanluTest1 的 PrintMessage 方法"); }
};
//---------------------------------------------------------------------------
class THsuanluTest2 : public THsuanluBase
{
public:
virtual void PrintMessage(void){ Form1->Memo1->Lines->Add(L"這是 THsuanluTest2 的 PrintMessage 方法"); }
};
//---------------------------------------------------------------------------
class THsuanluTest3 : public THsuanluTest2
{
public:
virtual void PrintMessage(void){ Form1->Memo1->Lines->Add(L"這是 THsuanluTest3 的 PrintMessage 方法"); }
};
- 定義 HsuanluFactory 時状原,由于自己寫的這些類的構(gòu)造函數(shù)沒有參數(shù)聋呢,所以模板參數(shù)只有一個公共父類 THsuanluBase
- 在程序開始執(zhí)行的時候,即主窗口的構(gòu)造函數(shù)里面注冊所有需要反射的類颠区,然后就可以使用類名字符串來創(chuàng)建這些類的對象了削锰。
THsuanluReflectionFactory<THsuanluBase> HsuanluFactory;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
HsuanluFactory.Register<THsuanluTest1>();
HsuanluFactory.Register<THsuanluTest2>();
HsuanluFactory.Register<THsuanluTest3>();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
THsuanluBase *p1 = nullptr, *p2 = nullptr, *p3 = nullptr;
try
{
p1 = HsuanluFactory.Create(L"THsuanluTest1");
p2 = HsuanluFactory.Create(L"THsuanluTest2");
p3 = HsuanluFactory.Create(L"THsuanluTest3");
p1->PrintMessage();
p2->PrintMessage();
p3->PrintMessage();
}
catch(Exception &e)
{
ShowMessage(e.Message);
}
delete p1;
delete p2;
delete p3;
}
運行結(jié)果:
相關(guān):
- C++ Builder 的反射 (三) - 通用 Reflection Factory
- C++ Builder 的反射 (一) - Reflection 簡單實現(xiàn)
- C++ Builder 獲取任意一個類或?qū)ο蟮念惷?/a>
- 枚舉控件所有的屬性、事件和方法
- 枚舉窗口內(nèi)所有的控件
- C++ Builder 的枚舉類型
- C / C++ 可變參數(shù)的函數(shù)
- C / C++ 可變參數(shù)的宏毕莱,__VA_ARGS__器贩,...
- C++ 可變參數(shù)的模板
- C++ Builder 的 PME 架構(gòu)
C++ Builder 參考手冊 ? C++ Builder 的反射 (二) - Reflection Factory