指向成员的指针不是很用,但它们非常强大,你怎么使用它们以及你做过的最酷的事情是什么?指向成员和成员函数的最佳用法是什么?
编辑: 这与其说是列出的东西都是可能的,例如上市的boost ::绑定和的boost ::功能并不好。相反,也许他们有一个很酷的用法?我知道他们自己很酷,但这不是这个意思。
指向成员的指针不是很用,但它们非常强大,你怎么使用它们以及你做过的最酷的事情是什么?指向成员和成员函数的最佳用法是什么?
编辑: 这与其说是列出的东西都是可能的,例如上市的boost ::绑定和的boost ::功能并不好。相反,也许他们有一个很酷的用法?我知道他们自己很酷,但这不是这个意思。
我曾经需要使用标准数据作为纯结构来操作,以便能够将所有标准列表存储在队列中。我必须将结构与GUI和其他过滤元素等绑定在一起。所以我想出了使用指向成员的指针以及指向成员函数的解决方案。
假设你有一个
struct Criteria
{
typedef std::string Criteria::* DataRefType;
std::string firstname;
std::string lastname;
std::string website;
};
比你可以用标准的领域,并与现场的字符串表示绑定
class Field
{
public:
Field(const std::string& name,
Criteria::DataRefType ref):
name_(name),
ref_(ref)
{}
std::string getData(const Criteria& criteria)
{
return criteria.*ref_;
}
std::string name_;
private:
Criteria::DataRefType ref_;
};
然后你就可以注册所有领域使用你只要想要:GUI,序列化,按字段名称进行比较等。
class Fields
{
public:
Fields()
{
fields_.push_back(Field("First Name", &Criteria::firstname));
fields_.push_back(Field("Last Name", &Criteria::lastname));
fields_.push_back(Field("Website", &Criteria::website));
}
template < typename TFunction >
void forEach(TFunction function)
{
std::for_each(fields_.begin(), fields_.end(),
function);
}
private:
std::vector<Field> fields_;
};
通过调用例如fields.forEach(serialization);
或
GuiWindow(Criteria& criteria):
criteria_(criteria)
{
fields_.forEach(std::bind1st(
std::mem_fun(&GuiWindow::bindWithGui),
this));
}
void bindWithGui(Field field)
{
std::cout << "name " << field.name_
<< " value " << field.getData(criteria_) << std::endl;
};
那么我使用标准算法定期使用指向成员函数的指针。就我而言,他们没有什么特别之处。
指向成员函数非常适合用的for_each
创建伪兰巴表达式vector<SomeClass*> v = getAVector();
for_each(v.begin(), v.end(), mem_fun(&SomeClass::print));
可以绑定成员变量和函数使用的boost ::绑定,让平常函子。
与他们接下来的工作将喜欢在通常的功能的使用:
除了上述之外,您可以将它们用作回调函数。
我和他们做过的最酷的事情,我很久以前做过。今天可能有更好的方法。
我为网络管理工具创建了一个自生成的命令行解析器。表示要管理的对象的类每个都有自己的子类表(名称,指向工厂成员的指针),实例(id,实例从列表中的指针)以及命令(名称,指向成员函数的指针)。这使得解析器来处理喜欢的事物:
SET NETWORK ROUTE 192.168.0.0 HOPS 1
或
QUERY NETWORK NAMESERVER servername
无需了解路线,或域名服务器什么。
我做了一个“DomainEditor”类这个庞大的应用程序,我写的。数据库中的所有类型(域)表都可以由程序的管理员编辑,并且由于客户端通过与其他名称不同的名称调用某些类型,我做了一个对话框,允许您编辑它们。好吧,我不想为15种以上的域类型编辑一个编辑器,所以我编写了一个可以将每个类转换为的超类,并且使用指针可以对每个域表进行简单调用。每个人都支持所有相同的属性,描述(名称),ID,非活动标志和必需标志。所以,代码开始与宏设置我的电话:
#define DomainList(Class, Description, First, Next, Item, UpdateItem, DeleteItem, IsItemRequired, MaxLength) { \
CWFLHandler *handler = new CWFLHandler; \
handler->pWFL = new Class;\
handler->LoadFirstType = (LoadFirst)&Class::First;\
handler->LoadNextType = (LoadNext)&Class::Next;\
handler->LoadType = (Load)&Class::Item;\
handler->UpdateType = (Update)&Class::UpdateItem;\
handler->DeleteType = (Delete)&Class::DeleteItem;\
handler->IsRequiredType= (IsRequired)&Class::IsItemRequired; \
handler->MAX_LENGTH = MaxLength;\
PopulateListBox(m_Domain, Description, (long)handler); }\
然后,大量的调用宏:(这里只是一个单一的一个)
DomainList(CConfigWFL, "Application Parameter Types", LoadFirstParameterType, LoadNextParameterType, LoadParameterTypeByTypeId, UpdateParameterType, DeleteParameterType, IsParameterTypeRequired, LEN_APPL_PARAMETER_DESC);
然后,调用编辑数据都是常见的,我根本不需要复制任何代码...
例如,要使用DropDownList中的选定项目填充列表(由宏填充),代码将显示像这样:
if((pWFLPtr->pWFL->*pWFLPtr->LoadFirstType)(true))
{
do
{
m_Grid.AddGridRow();
m_Grid.SetCheck(COLUMN_SYSTEM, (pWFLPtr->pWFL->*pWFLPtr->IsRequiredType)(pWFLPtr->pWFL->TypeId));
m_Grid.SetCheck(COLUMN_STATUS, pWFLPtr->pWFL->InactiveIndc == false);
m_Grid.AddTextToGrid(COLUMN_NAME, pWFLPtr->pWFL->TypeDesc);
m_Grid.AddTextToGrid(COLUMN_DEBUG, pWFLPtr->pWFL->TypeId);
m_Grid.AddTextToGrid(COLUMN_ID, pWFLPtr->pWFL->TypeId);
}
while((pWFLPtr->pWFL->*pWFLPtr->LoadNextType)());
当然,这些都存储在对话框的一部分。我只是创建了类的新实例,并将它们存储在ListBox的ItemData成员中。所以,当对话结束时,我确实必须清理所有这些。但是,我将该代码从此消息中删除。
来存储所有这些东西在课堂上被定义为:
typedef bool (CMyWFL::*LoadFirst)(bool);
typedef bool (CMyWFL::*LoadNext)();
typedef bool (CMyWFL::*Load)(long);
typedef bool (CMyWFL::*Update)(long, const char*, bool);
typedef bool (CMyWFL::*Delete)(long);
typedef bool (CMyWFL::*IsRequired)(long);
class CWFLHandler {
public:
CWFLHandler() {};
~CWFLHandler() { if(pWFL) delete pWFL; }
CMyWFL *pWFL;
LoadFirst LoadFirstType;
LoadNext LoadNextType;
Load LoadType;
Update UpdateType;
Delete DeleteType;
IsRequired IsRequiredType;
int MAX_LENGTH;
};
CWFLHandler *pWFLPtr;
所有这些工作使得它真的很高兴能够将新域添加到应用程序很少的工作,将其添加到域编辑...可能有更好的办法,我不知道。但这是我去的方式,它对我很好,恕我直言,这是非常有创意... :)
我用它们作为StructSerlialiser的一部分来填充SAX解析器事件的C++ POD结构,即将XML映射到C++数据模型。
template<class STRUCT, typename FIELDTYPE>
struct FieldBinderImpl : public FieldBinder<STRUCT>
{
typedef FIELDTYPE (STRUCT::*MemberPtr);
FieldBinderImpl (const std::string& tag, MemberPtr memberPtr)
: FieldBinder (tag)
, memberPtr_ (memberPtr)
{
}
virtual SerialiserBase* createSerialiser (STRUCT& data) const
{
return new Serialiser<FIELDTYPE> (&(data.*memberPtr_));
}
private:
MemberPtr memberPtr_;
};
template<class T>
class StructSerialiser : public SerialiserData<T>
{
public:
typedef std::vector<FieldBinder<T>*> FieldBinderList;
private:
static FieldBinderList fieldBinderList_;
protected:
template<typename FIELDTYPE>
static void bind (const std::string& tag, FIELDTYPE (T::* member))
{
fieldBinderList_.push_back (new FieldBinderImpl<T, FIELDTYPE> (tag, member));
if (tag.empty())
fieldBinderList_.back()->tags_ = Serialiser<FIELDTYPE>::getTags();
}
// ...
}
// ...
也有串行器双,字符串,向量等。要使用它,你只想绑定结构成员的名字,例如:
class Index
{
public:
std::string currency;
std::string name;
};
template<>
class Serialiser<Index> : public StructSerialiser<Index>
{
public:
Serialiser (Index* data) : StructSerialiser<Index> (data) {}
static void initialise()
{
bind ("currency", &Index::currency);
bind ("name", &Index::name);
}
};
你的意思是mem_fun_ref,不是吗? – dirkgently 2009-04-08 18:29:17