![](/img/trans.png)
[英]Using the PIMPL idiom, should the implementation always be a private member of the class?
[英]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”的特定方法時(為簡單起見,我在此不包括此較長的部分,因為它與錯誤無關,而只是描述此代碼段的目標)該方法可以執行操作,並通過指向函數的指針來調用其父對象“用戶”的私有方法(我希望這很清楚...)。
現在,我認為對象的初始化順序存在問題,但是我不確定在哪里以及如何修復它。 特別是我認為,由於“ 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 called\n"; }
~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 called\n";
}
~item() {}
// Method invoked externally
int callback() {
std::cout << "item class method callback invoked\n";
// 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 registered\n";
return 0;
}
}
// Method invoked externally
bool callback2() {
std::cout << "items class method callback2 invoked\n";
// 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 registered\n";
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 called\n";
}
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=0\n" << "END\n";
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.