命名参数习惯用法,使用指向类私有方法的指针
Named Parameter Idiom using a pointer to a class private method
我在做一些可能不是真正"常规"的事情时遇到了一个c++编译错误。为了使事情更容易,我只是重写了我试图以更容易阅读的方式使用的机制,我检查了我得到了同样的问题。
首先是代码:
test.h//-- c++ --
template <typename MODULE> class item;
template <typename MODULE>
class init {
public:
typedef int (MODULE::*funcPtr)(int);
private:
funcPtr m_fp;
public:
init& has_funcPtr(funcPtr fp) { m_fp = fp;}
init() {}
virtual ~init() {}
private:
friend class item<MODULE>;
};
template <typename MODULE>
class item {
public:
typedef int (MODULE::*funcPtr)(int);
private:
funcPtr m_fp;
public:
item(init<MODULE> params) : m_fp(params.m_fp) {}
virtual ~item() {}
};
class user {
public:
typedef init<user>::funcPtr funcPtr;
private:
// Method CB
int func1(int i);
// Item member
item<user> m_item;
public:
user();
virtual ~user();
};
test.cpp//-- c++ --
#include "test.h"
user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {}
int user::func1(int i) {return 1;}
,这里是错误:
/test.cpp:5:59: error: invalid use of non-static member function
user::user() : m_item(init<user>().has_funcPtr(this->func1) ) {
^
所以,我不确定这是实现我想要的最好的方法(可能不是,无论如何,如果你有其他建议,他们是非常欢迎的),但我现在的目标是使它工作或理解为什么它不能工作,这样我就能从中学到一些东西!
基本思想是:
- 类"item"可以使用命名参数习惯进行初始化,使用类"init"的"has_funcPtr"方法连接到它的构造函数,如"init().has_funcPtr(&function_name)"。
- 类"user"可以存储一个指向其私有方法"func1"的指针,作为其私有成员"item"类型的私有成员的私有成员。
通过这种方式,当调用对象"item"的特定方法时(为了简单起见,我没有在这里包括这个长部分,因为它与错误无关,但它只是描述这段代码的目标),该方法可以做一些事情,并通过指向函数的指针调用其父对象"user"的私有方法(我希望这足够清楚…)。
现在,我认为有一个问题与对象的初始化顺序,但我不知道在哪里以及如何修复它。特别是我认为,既然"func1"方法不操作类"user"的任何成员,那么它的引用可以直接在初始化列表中使用,初始化一个"init"对象,并将其提供给一个"item"对象。
提前感谢大家
this->func1
不构成成员函数指针。如果你在user
类中,它应该看起来像&user::func1
。
我把我的问题的完整答案贴在这里。根据Bo的建议,在理解了如何通过指针指向实例特定方法之后,我开发了它。
总之,有两件事非常重要:
-
指向非静态类成员函数的指针可以被认为只是一个偏移量,而不是一个"绝对地址"(http://www.codeguru.com/cpp/cpp/article.php/c17401/C-Tutorial-PointertoMember-Function.htm)。这意味着如果没有实例指针,就不能访问该函数(它只是一个偏移量)。一旦你有了实例指针,你就可以用这个"偏移指针"来调用这个方法:
(object_ptr->*method_ptr)(parameters_here)
更好的方法是使用#define宏,因为这种语法很容易出错,而且读起来很复杂(https://isocpp.org/wiki/faq/pointers-to-members):
)#define CALL_MEMBER_FN(ptrToObject,ptrToMember) ((ptrToObject)->*(ptrToMember))
,然后用作:
CALL_MEMBER_FN(object_ptr, method_ptr)(parameters_here)
-
遵循第一点,如果您希望嵌套类能够通过指向它的指针调用上层类方法,您还需要传递上层类实例指针来访问该函数。在我的例子中,因为我希望能够逐个决定是否应该调用该方法,所以我使用了命名参数习惯用法(例如,下面注意func2没有注册)。
最后这里是修改后的代码,它的工作(测试):
-- c++ -- test.h
#include <iostream>
template <typename MODULE> class item;
template <typename MODULE>
class init {
public:
typedef int (MODULE::*funcPtr)(int);
typedef bool (MODULE::*func2Ptr)(bool);
private:
funcPtr m_fp;
func2Ptr m_fp2;
MODULE* m_dad;
public:
init& has_funcPtr(funcPtr fp) { m_fp = fp; return *this;}
init& has_func2Ptr(func2Ptr fp2) { m_fp2 = fp2; return *this;}
init(MODULE* dad) : m_dad(dad) { std::cout << "init constructor calledn"; }
~init() {}
private:
friend class item<MODULE>;
};
template <typename MODULE>
class item {
public:
typedef int (MODULE::*funcPtr)(int);
typedef bool (MODULE::*func2Ptr)(bool);
private:
funcPtr m_fp;
func2Ptr m_fp2;
MODULE* m_dad;
public:
item(init<MODULE> params) :
m_fp(params.m_fp),
m_fp2(params.m_fp2),
m_dad(params.m_dad)
{
std::cout << "item constructor calledn";
}
~item() {}
// Method invoked externally
int callback() {
std::cout << "item class method callback invokedn";
// In the real case here do general stuff
if(m_fp) {
int i = (m_dad->*m_fp)(1); // call member function through its pointer
return i;
} else {
std::cout << "callback not registeredn";
return 0;
}
}
// Method invoked externally
bool callback2() {
std::cout << "items class method callback2 invokedn";
// In the real case here do general stuff
if(m_fp2) {
bool b = (m_dad->*m_fp2)(true); // call member function through its pointer
return b;
} else {
std::cout << "callback2 not registeredn";
return false;
}
}
};
class user {
public:
typedef init<user>::funcPtr funcPtr;
private:
// Methods that optionally add more functionalities to the 2 callbacks
int func1(int i);
bool func2(bool b);
public:
// Item member
item<user> m_item;
public:
user();
~user();
};
- c++ -- test.cpp
#include "test.h"
user::user() : m_item(init<user>(this).has_funcPtr(&user::func1) ) {
std::cout << "user constructor calledn";
}
int user::func1(int i) {return i;}
bool user::func2(bool b) {return b;} // func2 won't be registered
int main() {
user* u = new user();
// Test callbacks
int i = u->m_item.callback();
bool b = u->m_item.callback2();
std::cout << "main is printing i=" << i << " and b=" << b << "n";
std::cout << "expected results are i=1 and b=0n" << "ENDn";
return 0;
}
输出:init constructor called
item constructor called
user constructor called
item class method callback invoked
items class method callback2 invoked
callback2 not registered
main is printing i=1 and b=0
expected results are i=1 and b=0
END
- 将一个类的方法指针存储到另一个类中
- 如何获得GUID编码器,如果我在IMFTransform上有一个指针?
- 如何调用返回类方法指针的类方法
- 通过reinterpret_casting方法指针从指针调用派生类的方法。这是 UB 吗?
- 泛型方法指针.reinterpret_cast指向不同类的方法指针,这是 UB 吗?
- C++;类方法指针;λ;将 lambda 作为成员函数指针传递;
- 使用模板、方法指针和字符串键入推导
- C++ - 有人有分析指针到指针问题的技巧吗?
- 将方法指针作为整数参数发送到C#的C 方法
- 是否有功能指针的爆炸
- 从C 中的VTable获取方法指针
- 为什么std::optional有类似指针的开销
- 我的类中有方法的指针数组,但我不能调用我的方法.代码如下
- 模板化方法指针 - 无法匹配函数参数的指针
- 获取特定的模板重载方法指针
- 如何将方法指针声明为Typedef方法参数
- RAII理解-有界指针的重音方法
- 如何将方法指针类型转换为函数指针类型
- 将方法指针传递给pthread_create时,我的方法签名有什么问题
- 是否有方法为任何指针类型定义转换操作符