假設目前有一個類
class Object {
public:
void function() const {
}
void function2() const {
}
};
Object::function是 "成員函數"
&Object::function是 "成員函數的地址"
現在有一種新的數據類型 void(Object::*)()叫做成員函數指針,它能夠被賦值"成員函數的地址"。
"成員函數指針"要指定物件Object、返回值void、形參()、函數修飾詞 如const,如此該指針能指到準確的函數,如果有函數這四個都一樣,那這個指針就可以指到它。
void (Object:: * funcPtr)() const = &Object::function;
//數據類型 void (Object3:: * )() const
//變量名稱 funcPtr
//初始化的值 &Object::function
//另外一個返回值 物件 形參 函數修飾詞 都一樣的函數 能夠賦值給funcPtr
funcPtr = &Object::function2;
//要使用成員函數指針,需要一個成員函數指針裡的函數一樣的類,和.*運算符。
//成員訪問運算符.*
//指針到成員訪問運算符->*
Object obj;
Object* objPtr;
(obj.*funcPtr)(); // 输出: Show method from Object
(objPtr->*funcPtr)();
由於是一種數據類型,所以可以在任何地方宣告出來,如果有物件有被初始化過的成員函數指針,那這個物件就會有能力去調用這個函數。
class B {
public:
void bFunction() const {
std::cout << "Calling B::bFunction" << std::endl;
}
};
class A {
public:
// 定义一个指向 B 类成员函数的指针
void (B::* bFuncPtr)() const = nullptr;
// 方法,允许 A 对象调用 B 的成员函数
void callBFunction(const B& b) const {
if (bFuncPtr != nullptr) {
(b.*bFuncPtr)(); // 使用成员函数指针调用 B 的成员函数
}
}
};
void funcPart14()
{
A a;
B b;
a.bFuncPtr = &B::bFunction;
a.callBFunction(b);
//或者說
(b.* (a.bFuncPtr))();
}
像在上方的代碼中,在A裡面宣告了一個變量,這樣A能使用B的函數。
這東西還能和模板一起用,這樣可以通用化返回值跟形參,更加強大。
class Object4 {
public:
void display() const {
std::cout << "Displaying Object4" << std::endl;
}
int count(int n) const {
return n;
}
};
// 模板类,用于持有任意类型成员函数的指针
template<typename ReturnType, typename... Args> //Args是數據類型
class MemberFuncPtr {
public:
ReturnType(Object4::* funcPtr)(Args...) const; // 成员函数指针
// 构造函数,用于初始化成员函数指针
MemberFuncPtr(ReturnType(Object4::* ptr)(Args...) const) : funcPtr(ptr) {}
// 调用成员函数的方法
ReturnType invoke(const Object4& obj, Args... args) const {
return (obj.*funcPtr)(args...);
}
};
void funcPart16()
{
Object4 obj;
MemberFuncPtr<void> displayPtr(&Object4::display);
displayPtr.invoke(obj); // 调用 Object4 的 display 方法
MemberFuncPtr<int, int> countPtr(&Object4::count);
int result = countPtr.invoke(obj, 42); // 调用 Object4 的 count 方法,并传入参数 42
std::cout << "Count result: " << result << std::endl;
}
->*是可以重載的,不過.*不能重載,不過未來我應該會寫一個c++ operator overloading的文章,這裡不講。
既然他是數據類型,那應該有類型轉換,不過好像非常侷限,沒什麼用。
class Object3 {
public:
void display() const {
std::cout << "Display method from Object3" << std::endl;
}
void show() const {
std::cout << "Show method from Object3" << std::endl;
}
};
void funcPart15()
{
// 创建指向 Object3::display 的成员函数指针
void (Object3:: * funcPtr)() const = &Object3::display;
// 进行类型转换至指向 Object3::show 的成员函数指针
funcPtr = (void(Object3::* )() const) &Object3::show;
funcPtr = & Object3::show;
//這兩行是一樣的
// 使用转换后的指针调用函数
Object3 obj;
Object3* objPtr;
(obj.*funcPtr)(); // 输出: Show method from Object3
(objPtr->*funcPtr)();
//error 不能這樣做
//A a;
//(a.*funcPtr)();
}
總結一下,
使用上來說,就是
返回值(物件::* 變量 )(形參) 修飾詞;
返回值(物件::* 變量 )(形參) 修飾詞 = &物件::函數。
該函數的 返回值 物件 形參 修飾詞 都要和成員函數指針宣告的 返回值(物件::* 變量 )(形參) 修飾詞一樣。(或者用模板)
然後,使用
(物件.*變量)(形參);
或
(物件指針->*變量)(形參);來調用函數
然後加上模板就變成,這個指針可以指向很大範圍的函數。
ReturnValue (物件::* 變量) (Arg...)函數修飾詞;