Magic C++ (函数指针)(xml配置控件样式)

2014-11-24 02:47:01 · 作者: · 浏览: 1

问题起源:

我在业余时间编写基于WTL的控件重绘,为了灵活设置控件的各种样式,我选择了使用xml来配置控件的样式(比如文字颜色,字体,背景颜色)。其中build.xml用来设置控件类型、位置、文字、样式,skin.xml来设置颜色、字体、图片。

首先定义一个类UIData,提供接口LoadCtrl(从build.xml读取位置信息)和LoadCss(从skin.xml读取样式)。

然后定义一个类ICtrl(继承UIData)作为控件基类,提供接口Create。

在IForm中提供一个接口Find

build.xml

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 ctrl_; 这个方法不行,根据string返回的只是指针,没有一个新的对象

So how?C++函数指针闪亮登场,让我不得不佩服C++ is magic,You can control it all by yourself !


[cpp]
#pragma once
#include
#include
#include
using namespace std;

class ICtrl
{
public:
virtual void Print(){ cout<<"ICtrl"< };

class ILabel : public ICtrl
{
public:
virtual void Print(){ cout<<"ILabel"< };

class IButton : public ICtrl
{
public:
virtual void Print(){ cout<<"IButton"< };

inline ICtrl* NewLabel(){ return new ILabel(); }
inline ICtrl* NewButton(){ return new IButton(); }

typedef ICtrl* (*NewCtrl)();

class CContainer
{
private:
map 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
#include
#include
using namespace std;

class ICtrl
{
public:
virtual void Print(){ cout<<"ICtrl"< };

class ILabel : public ICtrl
{
public:
virtual void Print(){ cout<<"ILabel"< };

class IButton : public ICtrl
{
public:
virtual void Print(){ cout<<"IButton"< };

inline ICtrl* NewLabel(){ return new ILabel(); }
inline ICtrl* NewButton(){ return new IButton(); }

typedef ICtrl* (*NewCtrl)();

class CContainer
{
private:
map 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();
}