問題起源:
我在業余時間編寫基於WTL的控件重繪,為了靈活設置控件的各種樣式,我選擇了使用xml來配置控件的樣式(比如文字顏色,字體,背景顏色)。其中build.xml用來設置控件類型、位置、文字、樣式,skin.xml來設置顏色、字體、圖片。
首先定義一個類UIData,提供接口LoadCtrl(從build.xml讀取位置信息)和LoadCss(從skin.xml讀取樣式)。
然後定義一個類ICtrl(繼承UIData)作為控件基類,提供接口Create。
在IForm中提供一個接口Find
build.xml
<main type="Form" rect="0,0,500,400" css="public">
<label type="Label" rect="0,0,120,20" text="hello" css="public">
</main>
ICtrl* Find(const string name); 將name傳入後在Find內部先找出該name對應的type,接著發現該type是Label於是new ILabel,之後再LoadCtrl(該函數最後會調用LoadCss的),最後返回這個ILabel(也可以在返回前調用Create)。
上面是鋪墊,下面是問題:在Find中,傳入一個name讀取對應的type之後,如何只用一步就返回一個new ILabel?
常規做法:
ICtrl* c = nullptr;
if(type == "Label") c = new ILabel;
else if(type == "Button") c= new IButton();
.... return c; 方法可行,只是每次都得做很多次if比較
或者
map<string, ICtrl*> ctrl_; 這個方法不行,根據string返回的只是指針,沒有一個新的對象
So how?C++函數指針閃亮登場,讓我不得不佩服C++ is magic,You can control it all by yourself !
[cpp]
#pragma once
#include <iostream>
#include <string>
#include <map>
using namespace std;
class ICtrl
{
public:
virtual void Print(){ cout<<"ICtrl"<<endl; }
};
class ILabel : public ICtrl
{
public:
virtual void Print(){ cout<<"ILabel"<<endl; }
};
class IButton : public ICtrl
{
public:
virtual void Print(){ cout<<"IButton"<<endl; }
};
inline ICtrl* NewLabel(){ return new ILabel(); }
inline ICtrl* NewButton(){ return new IButton(); }
typedef ICtrl* (*NewCtrl)();
class CContainer
{
private:
map<string, NewCtrl> ctrl_;
public:
void Register(const string class_name, NewCtrl method)
{
ctrl_[class_name] = method;
}
ICtrl* operator[] (const string class_name)
{
NewCtrl method = ctrl_[class_name];
return (*method)();
}
};
void magic_test()
{
CContainer magic;
magic.Register("Label", &NewLabel);
magic.Register("Button", &NewButton);
ICtrl* c = magic["Label"];
c->Print();
}
#pragma once
#include <iostream>
#include <string>
#include <map>
using namespace std;
class ICtrl
{
public:
virtual void Print(){ cout<<"ICtrl"<<endl; }
};
class ILabel : public ICtrl
{
public:
virtual void Print(){ cout<<"ILabel"<<endl; }
};
class IButton : public ICtrl
{
public:
virtual void Print(){ cout<<"IButton"<<endl; }
};
inline ICtrl* NewLabel(){ return new ILabel(); }
inline ICtrl* NewButton(){ return new IButton(); }
typedef ICtrl* (*NewCtrl)();
class CContainer
{
private:
map<string, NewCtrl> ctrl_;
public:
void Register(const string class_name, NewCtrl method)
{
ctrl_[class_name] = method;
}
ICtrl* operator[] (const string class_name)
{
NewCtrl method = ctrl_[class_name];
return (*method)();
}
};
void magic_test()
{
CContainer magic;
magic.Register("Label", &NewLabel);
magic.Register("Button", &NewButton);
ICtrl* c = magic["Label"];
c->Print();
}