成员指针不是很常用,但它们非常强大,你如何使用它们以及你做过的最酷的事情是什么?
修改 这并不是列出可能的事情,例如列出 boost :: bind 和 boost :: function 并不好。相反,也许他们很酷的用法?我知道他们自己很酷,但这不是这个。
答案 0 :(得分:5)
我曾经需要使用标准数据作为纯结构进行操作,以便能够存储队列中所有条件的列表。我不得不将结构与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;
};
答案 1 :(得分:3)
指向成员函数的指针非常适合使用for_each
创建伪lambda表达式vector<SomeClass*> v = getAVector();
for_each(v.begin(), v.end(), mem_fun(&SomeClass::print));
答案 2 :(得分:3)
我做过的最酷的事情,我很久以前做过的。今天可能有更好的方法。
我为网络管理工具创建了一个自生成的命令行解析器。表示要管理的对象的类都有自己的子类表(名称,指向工厂成员的指针),实例(id,指向列表中实例的指针)和命令(名称,指向成员函数的指针) )。这使得解析器可以处理以下内容:
SET NETWORK ROUTE 192.168.0.0 HOPS 1
或
QUERY NETWORK NAMESERVER servername
不了解路线或名称服务器。
答案 3 :(得分:1)
我使用标准算法定期使用指向成员函数的指针。就我而言,他们没什么特别的。
答案 4 :(得分:1)
您可以使用boost :: bind绑定成员变量和函数,并获得通常的仿函数 下一步与他们合作将喜欢通常的功能用法:
答案 5 :(得分:0)
除了上一个之外,您还可以将它们用作回调函数。
答案 6 :(得分:0)
我在“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;
所有这些工作使得能够将新域添加到应用程序非常好,只需要很少的工作就可以将它们添加到域编辑器中......可能有更好的方法,我不知道。但这就是我去的方式,它对我来说非常好,恕我直言,它非常有创意...... :)
答案 7 :(得分:0)
我使用它们作为StructSerlialiser的一部分,从SAX Parser事件中填充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 ();
}
// ...
}
// ...
还有用于双重,字符串,向量等的Serialiser。要使用它,您只需将struct成员绑定到名称,例如:
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);
}
};