C++類成員指針的實(shí)現(xiàn)示例
一、類成員指針的核心定位
類成員指針是C++中專門指向“類的成員”(而非具體對(duì)象的成員)的特殊指針,和普通指針的核心區(qū)別:
- 普通指針:直接指向內(nèi)存中的某個(gè)地址(如變量、函數(shù)的入口地址);
- 成員指針:不直接指向內(nèi)存地址,而是存儲(chǔ)“成員在類中的偏移量”,必須綁定具體對(duì)象/對(duì)象指針后才能訪問(wèn)(因?yàn)轭惖某蓡T屬于對(duì)象,而非類本身)。
二、數(shù)據(jù)成員指針
1. 定義語(yǔ)法
指向類的非靜態(tài)數(shù)據(jù)成員的指針,語(yǔ)法格式:
// 格式:類名::* 指針變量名
類型 類名::* 數(shù)據(jù)成員指針名 = &類名::數(shù)據(jù)成員名;
2. 完整示例(可直接運(yùn)行)
#include <iostream>
using namespace std;
class Person {
public:
string name;
int age;
static int count; // 靜態(tài)數(shù)據(jù)成員(特殊情況)
};
int Person::count = 0; // 靜態(tài)成員初始化
int main() {
// 1. 定義并賦值:指向Person的age成員
int Person::*p_age = &Person::age;
// 指向Person的name成員
string Person::*p_name = &Person::name;
// 2. 綁定對(duì)象訪問(wèn)(用.*運(yùn)算符)
Person p1{"Alice", 20};
cout << "Name: " << p1.*p_name << endl; // 輸出Alice
cout << "Age: " << p1.*p_age << endl; // 輸出20
// 3. 綁定對(duì)象指針訪問(wèn)(用->*運(yùn)算符)
Person* p2 = &p1;
p2->*p_age = 21; // 修改age
cout << "New Age: " << p2->*p_age << endl; // 輸出21
// 4. 靜態(tài)數(shù)據(jù)成員指針(特殊:和普通指針一樣)
int* p_count = &Person::count; // 無(wú)需Person::*,直接用普通指針
*p_count = 100;
cout << "Count: " << Person::count << endl; // 輸出100
return 0;
}
3. 關(guān)鍵注意點(diǎn)
- 數(shù)據(jù)成員指針的類型必須嚴(yán)格匹配(如
int Person::*不能指向string Person::*); - 靜態(tài)數(shù)據(jù)成員不屬于對(duì)象,因此指向靜態(tài)數(shù)據(jù)成員的指針是普通指針,而非成員指針;
- 空類/無(wú)數(shù)據(jù)成員的類,其數(shù)據(jù)成員指針的偏移量為0,但依然是合法的成員指針。
三、成員函數(shù)指針
1. 定義語(yǔ)法
指向類的非靜態(tài)成員函數(shù)的指針,語(yǔ)法格式(需匹配返回值、參數(shù)列表、const/volatile限定):
// 格式:返回值 (類名::*)(參數(shù)列表) [const/volatile]
返回值 (類名::* 函數(shù)指針名)(參數(shù)列表) [const] = &類名::成員函數(shù)名;
2. 完整示例(含const成員函數(shù))
#include <iostream>
#include <string>
using namespace std;
class Calculator {
public:
int add(int a, int b) { return a + b; }
int sub(int a, int b) const { return a - b; } // const成員函數(shù)
static int mul(int a, int b) { return a * b; } // 靜態(tài)成員函數(shù)
};
int main() {
// 1. 指向非const成員函數(shù)
int (Calculator::*p_add)(int, int) = &Calculator::add;
// 2. 指向const成員函數(shù)(必須加const限定)
int (Calculator::*p_sub)(int, int) const = &Calculator::sub;
// 3. 綁定對(duì)象調(diào)用(.*運(yùn)算符)
Calculator calc;
cout << "Add: " << (calc.*p_add)(10, 5) << endl; // 輸出15
cout << "Sub: " << (calc.*p_sub)(10, 5) << endl; // 輸出5
// 4. 綁定對(duì)象指針調(diào)用(->*運(yùn)算符)
Calculator* p_calc = &calc;
cout << "Add via ptr: " << (p_calc->*p_add)(20, 3) << endl; // 輸出23
// 5. 靜態(tài)成員函數(shù)指針(特殊:和普通函數(shù)指針兼容)
int (*p_mul)(int, int) = &Calculator::mul;
cout << "Mul: " << p_mul(4, 5) << endl; // 輸出20
return 0;
}
3. 關(guān)鍵注意點(diǎn)
- 成員函數(shù)指針的括號(hào)不可省略:
(calc.*p_add)(10,5)不能寫成calc.*p_add(10,5)(運(yùn)算符優(yōu)先級(jí)問(wèn)題,.和->*優(yōu)先級(jí)低于()); - const成員函數(shù)的指針必須加
const限定,否則不匹配(如int (Calculator::*)(int,int) const不能賦值給int (Calculator::*)(int,int)); - 成員函數(shù)隱含
this指針,因此必須綁定對(duì)象才能調(diào)用(靜態(tài)成員函數(shù)無(wú)this,故無(wú)需綁定); - 成員函數(shù)指針的大小可能大于普通指針(如64位系統(tǒng)可能占16字節(jié)),因?yàn)樾枰鎯?chǔ)函數(shù)地址+this調(diào)整信息(多繼承場(chǎng)景)。
四、將成員函數(shù)用作可調(diào)用對(duì)象
成員函數(shù)指針本身不能直接作為“無(wú)上下文的可調(diào)用對(duì)象”(如傳給std::thread、std::function、std::for_each等),必須綁定對(duì)象/this指針,常用3種方式:
1. 方式1:std::bind(C++11及以上)
最經(jīng)典的方式,將成員函數(shù)與對(duì)象綁定,生成可調(diào)用的函數(shù)對(duì)象:
#include <iostream>
#include <functional> // 必須包含
using namespace std;
class Printer {
public:
void print(string msg, int num) {
cout << msg << ": " << num << endl;
}
};
int main() {
Printer p;
// 綁定成員函數(shù)+對(duì)象,固定部分參數(shù)(也可留空參數(shù)用placeholders)
auto func = bind(&Printer::print, &p, "Number", placeholders::_1);
// 調(diào)用:只需傳未綁定的參數(shù)
func(100); // 輸出Number: 100
return 0;
}
2. 方式2:std::function適配
將成員函數(shù)指針+對(duì)象封裝為std::function,適配通用可調(diào)用接口:
#include <iostream>
#include <functional>
using namespace std;
class Math {
public:
int square(int x) { return x * x; }
};
int main() {
Math m;
// 封裝為std::function:參數(shù)列表要匹配成員函數(shù)(隱含this已綁定)
function<int(int)> f = bind(&Math::square, &m, placeholders::_1);
cout << f(5) << endl; // 輸出25
// 也可直接用lambda(更簡(jiǎn)潔,見方式3)
function<int(int)> f2 = [&m](int x) { return m.square(x); };
cout << f2(6) << endl; // 輸出36
return 0;
}
3. 方式3:lambda表達(dá)式包裹(推薦,C++11+)
最簡(jiǎn)潔、易讀的方式,用lambda捕獲對(duì)象/this,包裹成員函數(shù)調(diào)用:
#include <iostream>
#include <thread> // 用于演示線程調(diào)用成員函數(shù)
using namespace std;
class Worker {
public:
void work(int id) {
cout << "Worker " << id << " is running" << endl;
}
};
int main() {
Worker w;
// 1. 普通調(diào)用:lambda捕獲對(duì)象
auto func = [&w]() { w.work(1); };
func(); // 輸出Worker 1 is running
// 2. 線程調(diào)用成員函數(shù)(核心場(chǎng)景)
thread t([&w]() { w.work(2); });
t.join(); // 輸出Worker 2 is running
// 3. 捕獲this(成員函數(shù)內(nèi)調(diào)用)
class Test {
public:
void call_self() {
auto f = [this]() { this->work(3); };
f(); // 輸出Worker 3 is running
}
void work(int id) { cout << "Test Worker " << id << endl; }
};
Test tst;
tst.call_self();
return 0;
}
4. 典型場(chǎng)景:成員函數(shù)作為算法的回調(diào)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Filter {
public:
bool is_even(int x) { return x % 2 == 0; }
};
int main() {
vector<int> nums = {1,2,3,4,5};
Filter f;
// 用lambda包裹成員函數(shù),作為find_if的謂詞
auto it = find_if(nums.begin(), nums.end(), [&f](int x) {
return f.is_even(x);
});
if (it != nums.end()) {
cout << "First even number: " << *it << endl; // 輸出2
}
return 0;
}
五、核心對(duì)比:成員指針 vs 普通指針
| 特性 | 普通指針(如int*、void(*)(int)) | 類成員指針(如int A::、void (A::)(int)) |
|---|---|---|
| 指向目標(biāo) | 內(nèi)存地址(變量/函數(shù)入口) | 類成員的偏移量(需綁定對(duì)象) |
| 大小 | 固定(64位=8字節(jié)) | 可能更大(如多繼承場(chǎng)景=16字節(jié)) |
| 調(diào)用/訪問(wèn)方式 | 直接解引用(*p、p()) | 需綁定對(duì)象,用.* / ->* 運(yùn)算符 |
| 靜態(tài)成員適配 | 完全兼容 | 靜態(tài)成員的指針等價(jià)于普通指針 |
| this指針 | 無(wú) | 非靜態(tài)成員函數(shù)指針隱含this,需綁定對(duì)象 |
總結(jié)
- 成員指針本質(zhì):存儲(chǔ)類成員的偏移量,而非直接內(nèi)存地址,必須綁定對(duì)象才能訪問(wèn)/調(diào)用;
- 語(yǔ)法關(guān)鍵:數(shù)據(jù)成員指針用
類名::*,成員函數(shù)指針需匹配返回值/參數(shù)/const限定,調(diào)用用.*/->*; - 可調(diào)用對(duì)象適配:優(yōu)先用lambda表達(dá)式包裹成員函數(shù)(簡(jiǎn)潔無(wú)坑),其次用
std::bind,避免直接傳遞成員函數(shù)指針; - 特殊情況:靜態(tài)成員的指針等價(jià)于普通指針,無(wú)需綁定對(duì)象即可使用。
到此這篇關(guān)于C++類成員指針的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)C++類成員指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
visual?studio?2022?編譯出來(lái)的文件被刪除并監(jiān)視目錄中的文件變更(示例詳解)
這篇文章主要介紹了visual?studio?2022?編譯出來(lái)的文件被刪除?并監(jiān)視目錄中的文件變更,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08
C++?BoostAsyncSocket實(shí)現(xiàn)異步反彈通信的案例詳解
這篇文章主要為大家詳細(xì)介紹了C++?BoostAsyncSocket如何實(shí)現(xiàn)異步反彈通信,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的可以了解一下2023-03-03
C++之類和對(duì)象課后習(xí)題簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇C++之類和對(duì)象課后習(xí)題簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-07-07
C++虛函數(shù)的實(shí)現(xiàn)機(jī)制分析
這篇文章主要介紹了C++虛函數(shù)的實(shí)現(xiàn)機(jī)制分析,需要的朋友可以參考下2014-07-07
C語(yǔ)言編程gcc如何生成靜態(tài)庫(kù).a和動(dòng)態(tài)庫(kù).so示例詳解
本文主要敘述了gcc如何生成靜態(tài)庫(kù)(.a)和動(dòng)態(tài)庫(kù)(.so),幫助我們更好的進(jìn)行嵌入式編程。因?yàn)橛行r(shí)候,涉及安全,所以可能會(huì)提供靜態(tài)庫(kù)或動(dòng)態(tài)庫(kù)供我們使用2021-10-10

