3 ^, a; B( [# D3 l$ N# r; R0 s f . c& A( J' S2 I. V4 m8 K很自然地,多维数组也支持用1维数组的方式去初始化。8 D9 y4 n4 ~' m4 c
8 c6 {2 [3 @' Z! {
int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; # h$ T2 I1 I0 `既然多维数组与1维数组没什么区别, 为什么还需要多维数组?# V7 F6 S( {# s+ F$ N( C. r) C
7 z, Z& M! B, D) M6 Z4 J, j7 F
假设有一幅RGB图像720*576个像素,每个像素有RGB三个通道,每个通道的值是8bit大小。给出图像的首地址p_rgb_image, 我们要取第40行,第50个像素的R,G,B值。代码如下: 6 |) _9 `, Z. l3 b5 o1 E, g, @5 ]$ o, ?$ {
unsigned char* p_rgb_image;0 ~! ?7 V$ W, G# K+ @$ |: B
unsigned char r = p_rgb_image[40*720*3 + 50 + 0];0 r% s$ z4 D7 ]% E
unsigned char g = p_rgb_image[40*720*3 + 50 + 1]; & [3 x- q P5 a5 ounsigned char b = p_rgb_image[40*720*3 + 50 + 2];* f( X4 P8 w* }
类似这样的场景, 采用多维数组的写法, 有点类似以索引为参数,可读性更高。相当于程序员和编译器打了一个配合。( d6 {8 N$ S7 @4 s
" m( k E: t3 H# z9 h ^; Denum 0 a# }* r; y" h{% s- ]) h4 F9 q: a- a# h
Red = 0,1 S% e; v( [8 Y& C) `
Green = 1,4 c* B6 {+ {% | V9 K
Blue = 2 " q; k. a4 O- _}; * K4 v& s: b: W! c6 J3 f0 n$ }unsigned char rgb_image[576][720][3]; / L1 l( c" M" M4 eint row = 40;) E* G2 T( F# g7 z3 b
int col = 50; : `% T! |5 u z( X) punsigned char r = rgb_image[row][col][Red]; # x7 x. b* Z4 c, o8 B# J$ t5 kunsigned char g = rgb_image[row][col][Green];, Q" F2 j5 L& v( p( @8 g
unsigned char b = rgb_image[row][col][Blue];- j: g- K0 l! C# q) k
数组指针以及与指针数组的区别# U3 _8 a! u* U7 G2 d9 a; o- q
数组指针,是一个指针, 指向的对象是数组。 数组指针的赋值,要求数组的长度匹配,否则会报错。当指向1维数组时, 需用用*取得数组对象的引用,再用下标来访问数组元素。 $ _9 q8 j, J! T1 F; e* F指针数组,是一个数组, 数组保存的元素的类型是指针。4 r, } f. { W& P) y
数组指针的定义: Z$ q4 ]( g# M# {
数组指针定义先定义一个数组。6 b) e. I% _, d3 p$ r5 a4 c
int a[10];' [) l3 v. M( I) |" p5 W9 n7 }
然后对数组里的名称用括号括起来后再在变量名称前面加个*号 8 m2 z2 X* K/ f) d1 `5 v! cint (*a)[10];: H" Q" ^1 z; \3 J u+ b9 X
后面你会发现函数指针定义类似。 ) {2 C# L3 G' `/ h' B7 ?( V// 各类定义对比 3 I( N# O+ C& q& xint a, *b, **c, d[10], e[10][20], *f[10], (*g)[10], *(*h)[10]; : M0 X$ L3 l/ d7 T4 B+ s( ?0 G: n7 l4 x) j* s: G
int *f[10]; // 指针数组, f是包含10个元素的数组, 数组里每一个元素的类型都是int* 8 r0 b" y% H1 N7 Xint *(f2[10]); // 指针数组。另外一种定义方式。! D4 V. ~4 ?" ?' `$ c
int(*f3[10]); // 指针数组。另外一种定义方式。: z( S8 e7 D8 H$ L
int(f4)[10]; // int数组$ g9 Q7 |/ d( F$ {7 J, ^
int(*g)[10]; // 数组指针, g是一个指针, 这个指针可以指向类型是int,元素个数是10的数组/ x! ]+ y0 F; D, A9 I
int* (*h)[10]; // 数组指针, h是一个指针, 这个指针可以指向类型是int*,元素个数是10的指针数组2 L& r; i$ X3 @. e! x5 ^2 W
# h* u; {8 [- a! y/ p
int d[10]; 4 E d; b% Q8 x& |g = &d;4 _8 R. S6 `+ Z( M) j
: Q2 ~& a( F, Q8 G5 \
int* e[10]; v! ]5 I: S: K" W) U3 e, lh = &e;0 Z# R8 I/ {+ }( `9 s
数组指针的使用 0 C& D0 b+ V" i* N. b ?数组指针一般先通过*号取得指针指向的数组对象, 然后再用下标操作访问元素。6 d, `3 C3 V* i/ M: L% d! w
& b$ t9 g3 E" Jint a[10]; ! I& X$ [& j. r. R2 N8 ^int(*p_ary)[10] = &a; // p_ary是一个指针, 指向"int (*)[10]"类型的数组$ i. G$ a W& B7 V x$ @( q) V
for (int i = 0; i < 10; i++) {" ^0 h% u. }3 F9 y, i* u
// p_ary是一个指向数组的指针, 需要先通过间接寻址运算符*(indirection operator)取得数组对象) ] R y1 O3 E2 R3 |4 z
// 再通过下标操作访问元素。* F# x- S9 J; J4 n$ O6 X2 I
(*p_ary) = i; ! m- J) R, J9 X7 A7 p0 X' S
} 2 \" f. t$ ?1 v D 6 W' {$ a$ S* v; d1 uint b[10]; 5 L! ~4 C2 m. x9 K4 s$ X/ \int c[20]; & B# q: G: t- D: u! A8 K8 ep_ary = &b; // 合法! l. G+ F5 l9 Q+ G
p_ary = &c; // 报错! 不能将 "int (*)[20]" 类型的值分配到 "int (*)[10]" 类型的实体 ( U1 z, u% u/ o- x数组指针指向多维数组的子数组% T+ N2 s6 x* k) A' M
int a[10];" ?" Y3 i6 c+ u# K- M
int b[4][10];9 J; n) z, h9 m
int(*p_ary)[10] = &a;7 }, P: W6 K- n$ F6 P
for (int i = 0; i < 10; i++) { , M3 C# d& Z6 U (*p_ary) = 1; 4 ^! }4 H) x" `/ |& k6 c9 Z6 c} " Y6 ], ^& b5 Y9 t: }1 e7 X5 q; S4 R, A8 h& `5 M8 N" y
p_ary = &b[2]; // 多维数组,可以看作数组的数组,4 i2 R5 Q4 n2 p. |' \, A
// b[2][0] ~ b[2][9]的值都被改成2了 x) e7 |' m+ }9 L# Zfor (int i = 0; i < 10; i++) { 3 J; Y) K* y' A- s: J2 ~ (*p_ary) = 2; + L6 \; E$ w% F. p2 m# p0 w( |; |}7 z% F& H3 y$ B9 x7 b# P. M
多维数组指针' q s2 X9 C$ Q/ W9 g1 h
多维数组指针,是一种指针,指向的对象是个多维数组,支持多个下标操作。0 d$ h! X/ T! j# \- K
o' ]/ s5 t$ V; E8 J
int a[2][5][10];* w2 \7 }+ K' D* ]% I
int(*p_ary1)[10] = &a[1][2]; // 1维数组指针 6 S8 C0 P8 r$ g! ]5 ]+ vint(*p_ary2)[5][10] = &a[1]; // 2维数组指针% x* j6 P( P9 x# J7 `
for (int row = 0; row < 5; row++) {% f" T0 P% g H+ q" X
for (int col = 0; col < 10; col++) { ! s* p" Q7 P+ ^+ Z- F; E (*p_ary2)[row][col] = row * col; ! [0 i ^" h: Z: c; X# j# ], ]) z& R/ J } . D$ D& D( m5 o. e, ?3 ]4 T4 g}0 R3 ~9 V! ^' s+ J
数组指针和指针数组对比实例 % L0 N* d7 g r1 E" Q2 J( V数组指针还是记住两步法即可 3 N% c! K- V: N. a( ?, b) U6 b- }- O4 \, S
定义一个数组 , d5 v' d/ ^9 b, _' k括号包围1中定义的名称,再在名称前加个*号。 ! q$ }9 u$ i, T1 K9 jint a[10]; " ^% I% B& N" R+ hint(*ary_pointer1)[10] = &a; // 数组指针 & ?/ r# T* T% S+ c2 u6 p lint* pointer_ary1[10]; // 指针数组。元素类型是int*8 M! n; O2 G9 r1 ?# K
int *(ponter_ary2[10]); // 指针数组。另外一种定义方式。& i; M8 K# S1 @3 h* x
int (*ponter_ary3[10]); // 指针数组。另外一种定义方式。 3 Y" T' X( Q1 gint c, *d, (*ary_pointer2)[10], *pointer_ary3[10]; // 排列定义比较。0 j* a" p: p2 g
; W; b S+ O. A6 |3 A// 指针数组可以把每个元素指向数组对应位置的地址。 U7 Y6 z' D% E( K5 j) t: m// 这样遍历指针数组, 可以达到遍历数组元素的效果,但是注意每个元素都是指针, 0 F( U$ q ]; t/ j1 i" S$ w// 需要访问原数组的值的话, 需要对指针用*间接寻址运算符。' {( i6 P( j2 ] k2 `5 x, h% `
int* pointer_ary[10]; 2 e$ Z3 A9 M/ F
for (int i = 0; i < 10; i++) { k, n2 F" h: K$ [
pointer_ary = &a;% p: z2 ^# y- w$ H$ U$ T/ C
}# _7 q7 @7 _7 K6 y' W
// 类似遍历原数组效果。7 e6 ^8 V% q5 }+ i( V
for (int i = 0; i < 10; i++) {" s( B" y5 c: ?/ b) L- }$ v
*pointer_ary = i; // 修改原数组。 : a6 `8 B4 F% [3 R! A9 |} / h7 I( u- h9 S ' p! o+ ]% y# p函数指针/ O% g5 k& B4 r* m9 C
取得函数地址 / [( g/ N: o M- r' e# A函数的名称作为参数被传递时,会隐式转换成函数指针, 和在函数名称前加取地址符&等价。建议带上更加统一和清晰。' w8 [% s+ J3 D L5 `* o/ T. j) L
& Z% j& u3 B" E8 Z+ pvoid f(int); ( @) X- x* f5 \1 Uint main() ; o4 E' J5 P! W( w. {7 p9 _7 J{- W( D; v- m+ A6 J9 W# r5 _+ b/ I0 h
void (*p1)(int) = &f;% ^- k0 `, |; o5 z
void (*p2)(int) = f; // same as &f " a2 G0 Y6 z* a return 0;' D! v) T* \( R3 R5 X
} 9 K1 h6 X: P( m0 ]7 f# \翻译成汇编代码, p1和p2的赋值是一样的。& W3 g m* l6 a9 \
3 s$ U1 d" Q3 n1 |8 `$ z- h
- V; X& ^+ a- l$ i! v* p7 [; d8 }
函数指针的声明5 D8 K/ X) s/ [1 b
单个函数指针变量定义步骤 I8 ^$ b l* Q定义一个函数。void fun1(int a, int b); int fun2(double a);% q( V' `6 A8 _
用括号把函数名称包围起来,然后在名称前面加*号。void (*fun1)(int a, int b); int (*fun2)(double a); 0 }# @, V8 e4 M3 J- p如果要定义函数指针数组,在定义单个函数指针的基础上,在名称后面加上[数组长度]void (*fun1[2])(int a, int b); int (*fun2[10])(double a); " J' b% d4 Q0 J% qtypedef定义函数指针 ! p8 E+ e0 O z' W- `& C可读性高比单个定义要高,特别是声明多个同类型的函数指针,或者函数指针数组。' [' ~3 n; d& B) O' g' N: c
, d7 E T0 S4 Z. w. J) U. h7 ytypedef定义函数指针的语法 $ V& M) l- R. ?! a4 C. H, _ wtypedef有两种做法, 一种就是定义一种函数对象,另外一种就是定义函数指针。用法稍稍不同,效果是一样。其中函数对象不支持赋值, 但是支持引用。+ c% _3 T/ o8 w' L
_" U* L2 }8 }, @
typedef int FuncObject(int a, int b); // FuncObject类型是函数对象 1 H* j6 W, y" e3 X; c. b9 ntypedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针, c* F" F, V, L, T
FuncObject* f1 = &Add;. I' e& N1 v2 }. L8 O+ z1 {
FuncPointer f2; , U) s" t+ t& y8 o1 W$ v; p0 E' Uf2 = f1; // f1, f2类型一样, 都是形式为int(int, int)的函数的指针。 ( @8 ^+ K8 N5 OFuncObject f3 = Add; // 报错! 函数对象不支持拷贝 ) g( {3 @& N5 cFuncObject f4 = &Add; // 报错!&Add是函数指针,与函数对象类型不匹配* b6 N6 y0 ?* H% T( M& i: Z/ I) r
FuncObject& f5 = Add; // 正确 5 {: P) p e1 I, n Uint ret = f5(2, 3); // 正确 C4 [8 X/ x- v: J1 t0 [5 [2 NFuncObject& f6 = &Add; // 报错!&Add是函数指针,与函数对象引用类型不匹配6 p7 k" Q- \2 [3 h" X# c
如何记住typedef定义函数指针的步骤 ; ~+ I+ t+ @0 x Z1 j) v& H, F5 f像定义一个函数指针那样, 指定一个名称。int (*CalFun)(int a, int b);! ^1 {$ `3 }# ?0 @+ h. ^1 [/ D
在这个函数指针变量声明前面加上typedef。typedef int (*CalFun)(int a, int b);# F6 b( C' K. W: v) _
完整例子% m% O' x7 K. e) j' V
typedef int(*CalFun)(int a, int b); % o/ M2 m; _" {/ [0 s9 H' W# e2 j0 s, ~- l9 }- p9 ?) e
int Add(int a, int b) 4 a2 n- k) V- }; q; w{9 v1 T$ O; E: T8 u; n/ X2 V
return (a + b); 1 x; V0 }7 ?( j+ Z} % H! N5 p7 O5 s; Y8 N! e+ T* \: H' @; R4 q, R5 R1 e
int Sub(int a, int b)# D0 Z) [" h: v% [. P2 }
{ ! b) `0 w7 x9 ^( [' S) _! W; z, W return (a - b); ; h8 H0 d5 `$ W7 W) r4 M) m3 k}% ~! x* Z: c% g" a N* w
9 b( o; ~6 a Q# Cint main(int argc, char** argv)7 t6 K7 d" j. F$ ^: n' y8 w
{ ) L/ {- r2 F4 Z0 p9 } CalFun f1 = Add; $ p2 L8 q( \+ s0 s, f/ Z. E CalFun f2 = Sub; 7 c- r3 t$ Y* S7 f int a = f1(2, 3); . ]6 d0 e Q1 M* w int b = f2(10, 5); O3 l% k& m1 K3 q. U, @( L
' \. ]6 P( c9 h9 L6 p // typedef定义的函数指针数组。1 Z; ]6 Z: S( b- z/ D* ]
CalFun f_ary[2];. {, x6 k) E; c# P1 Y, J
f_ary[0] = Add; 6 h& s2 z" B8 M! H f_ary[1] = Sub; " G' F+ ]: o% i* _! D- Y . I. M. z1 Z9 n9 j5 T9 o // 单个定义的函数指针数组。) l' Q, d$ x* h6 v! x8 _
int(*f_ary2[2])(int a, int b);9 H, h- V8 b* L" A
f_ary2[0] = Add;/ ~6 Y# I# F/ O/ p) y3 Z& v8 h; M
f_ary2[1] = Sub; 9 `+ N7 v' Y2 C+ v% C& Q7 E. e% j; n- T
return 0; 1 x3 @' O8 Q" n- K}+ a" x$ p% l) u# o1 z
/ A/ M$ {/ }7 n) V( M' F& \, r0 C
using别名定义函数指针: V" n: i0 L- ]. w' D
c++11以后的类型别名定义--using也可以用于定义函数指针, typedef的好处它都有,个人感觉比typedef更直观。using类型别名同样分函数对象和函数指针两种方式。) C9 w3 G5 { u$ y# G n9 O4 H& N& ^
~* Y" O6 d4 E Q; a
typedef int FuncObject(int a, int b); // FuncObject类型是函数对象 1 s: N3 @# z4 \7 ]3 nusing FuncObject = int(int a, int b);( T: E. ]5 ^# r+ W7 ]" D
typedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针 / m" {6 F0 n& P/ S5 F- busing FuncPointer = int(*)(int a, int b);" X& p1 P6 \1 ~" E- B, N+ K4 D
函数指针的调用 2 v$ U* |$ j0 B1 }函数指针和函数对象都可以直接后加括号调用 L+ x$ C& l. Z ~8 l; p# C; {4 W
int f(); : \+ V/ Y' X+ U yint (*p)() = f; // pointer p is pointing to f; v8 X4 k. ^. i3 K
int (&r)() = *p; // the lvalue that identifies f is bound to a reference $ @' Z1 m: c. Q" K/ or(); // function f invoked through lvalue reference0 j- G& J/ L$ k
(*p)(); // function f invoked through the function lvalue + O! h$ w7 d, Rp(); // function f invoked directly through the pointer9 J2 N' R4 O2 a, n! B; }
如果函数有重载, 函数指针会指向匹配的那个版本。9 o9 Q6 f1 r' Z& f8 ]+ M4 L
template<typename T>" o" |* U. M# l6 k
T f(T n) { return n; }/ z- \4 ~: V0 C9 F
0 `5 C! `' |) o* g0 `double f(double n) { return n; } : {, j m: l* n0 b' j9 J! q& l0 W # }( _$ M1 ^/ H& |* nint main()7 |3 N" g' A- t! B/ c3 `) K
{( l+ X( j, F3 B
int (*p)(int) = f; // instantiates and selects f<int> V; L. z7 l% Y1 y* }' W
}0 b5 F( l; I) M( b
成员函数指针 3 R9 a( c, |; n- ?$ V静态成员函数,除了增加了访问控制以外,跟普通的函数指针没什么区别,所以普通函数指针可以直接指向类的静态成员函数。但非静态的成员函数与普通函数指针不太一样,声明时需要指定函数归属的类名,并且调用需要指定对象实例。% F( v) A9 w- T1 ]4 d
8 h$ d2 D4 f/ K' }5 ?成员函数指针定义。 ; J: [/ @9 A3 H4 y' b, z像定义类成员函数实现那样写, 并任意指定名称,这里作func。void ClassName::func(int);, J; b- b; T- p% ?, }0 a
括号把类名、范围解析运算符::、名称包围起来。void (ClassName::func)(int);, S4 c- `- S# P( D" Y- V8 i
在名称的前面加个*号void (ClassName::*func)(int); 1 W+ S+ m: `) Z8 q, v成员函数也支持typedef和using的定义方式。typedef void(C::* MemberFunc)(int); using MemberFunc = void(C::*)(int);1 y, {8 x1 t' s6 n, v
成员函数指针如何调用。 3 ~0 p2 j+ U& C ?9 g, X/ t8 l假设成员函数指针名字为func1 F6 x4 Z0 o/ o
2 G8 d$ |( A3 a) V* r
void (ClassName::*func)(int);7 b/ y7 E3 D$ c* s7 E
对象式调用。 ) m8 y. `7 B, x: A' M: uClassName c; // 被调用的对象 % l$ I& U( s9 L6 w/ D, l成员函数指针名字当作正常函数那样写。 % \$ ]: y$ M9 y. yc.func(3); 8 O0 e5 N4 N$ s" G( e成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。 6 O, U! C4 R* oc.*func(3); 6 V- a7 c4 X) p3 `6 K. @4 q" ]最后用括号把调用对象、成员访问运算符.、间接寻址运算符*、和成员函数指针的名称包围起来。 6 ^! t+ I; Q9 q) ]8 j7 @(c.*func)(3);/ Y: N) s/ S" s+ O* x2 A
为何要加上括号? 根据c++的优先级标准,取成员运算符. > 函数调用() > 间接引用符*。 *号优先级比函数调用要低, 成员函数指针还没取得对象就被调用了,自然报错。 另外 ; _7 i) x- S- O: C# q/ x(c.(*func))(3); 0 f4 m7 E$ F3 a这样的写法也不行。 .*和->*是整体作为一个运算符的,中间不能用括号隔开。 $ O; @0 W" k* K1 u. @5 G指针式调用1 C$ `: i |$ D' ]5 ^( r
ClassName* p; // 被调用的对象的指针 4 c% r" x: J0 Z# Q8 e A成员函数指针名字当作正常函数那样写。. B Q* A4 I4 ]3 U$ Y; Q
p->func(3); 6 Z2 @' @/ G- ~2 b成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。 ; S q) G6 H2 Z6 N# U* n2 Ap->*func(3); ' o2 l7 I% s! S# b+ ]最后用括号把调用对象、成员访问运算符->、间接寻址运算符*、和成员函数指针的名称包围起来。 $ V0 Y* L5 u4 z. r(p->*func)(3);9 E/ c# t& _% O" f# N5 V- Q# a2 }
函数指针使用完整例子 0 ~" ~5 I% R$ R0 M5 i5 t5 |/ y# tstruct Cal & [6 Y( P( P7 k{ $ k7 _7 X1 ]2 X- Q int add(int a, int b); $ `0 F7 k1 x$ I4 S
int sub(int a, int b); 9 n- Y2 Z# g# B5 @3 U- h. E};( D& ^4 l) c# J6 N
1 `# N x6 n) A2 v4 e( J+ o& Lint main()* \8 P) }) v% h4 f2 }5 g" s
{3 M3 J! q4 P" j4 `3 f4 J
int (Cal::*fun)(int, int) = &Cal::add; 2 x* |& K% n. ^3 w7 E2 q3 k fun = &Cal::sub; 8 p7 m2 n0 w' Q . Z! i/ ~+ W6 }* _+ a0 L Cal* p_cal = new Cal(); . k* g2 U) q' Y3 k* b int r1 = (p_cal->*fun)(2, 3);0 [0 |' ^: Q9 P: B3 t7 s
delete p_cal; - z" k* g9 M5 `( k; u) `1 D3 Y% E: T. K 8 a' L6 k+ ]9 {4 ^ x0 N( T Cal local_cal; $ i# p* T' K! Y int r2 = (local_cal.*fun)(8, 6);5 W9 I( ^+ F) h- j% K7 {% E
} 3 _) G+ z/ ~, ?. C# M' n % d# \ h3 s4 |4 S. z* s$ }成员变量指针 $ U9 N. U) B$ k+ e成员变量指针比成员函数指针还要简单些,没有函数调用, 无需考虑函数调用和间接引用符*的优先级问题。 3 `' S( _+ o' n3 i: C. ~2 `3 z! c ' c. I5 \; W( R) T3 d$ {成员变量指针的定义 - a) {- |5 d6 }假如以下结构体C。3 R4 y8 y6 ]7 p: U+ j6 r+ E
0 f1 s% P% I: Q; nstruct C ; y) y: H8 g7 E& F m. y{ * q; K. k: g; f; L, |
int m; ' @3 `6 T3 n! i$ i! c}; * C, Z/ ]6 N5 R, Q: `8 i单个成员变量指针定义 $ F$ ?2 E! L6 {/ s' T
假设名称为p, 类似静态成员变量定义那样声明* f" q5 r# z* g
int C::p; % f$ l# t; b, S% t4 _' N在名称前面加上指针标识号* + ?! d$ y/ g5 P" }, o) n9 ?int C::*p; # R: ?4 D& e, d9 [6 X7 L1 L& mtypedef或using方式定义 : m9 ^1 J7 x9 ]( s/ u* {7 Utypedef int C::*MemberPointer; 2 t+ a- M. n' O# q. x" L; I$ H1 Iusing MemberPointer = int C::*;9 M; |6 _) H, o0 M* V9 o# o
成员变量指针的使用。 5 O9 l+ V) n0 l- ?& }3 Z# J! o类似成员函数指针那样,直接使用指向成员的指针运算符:.* 和->*即可。 9 z1 o1 i5 {+ Z# u成员变量指针, 能让我们实现一些遍历成员的动态功能。 例如把一个类/结构体的多个同类型的成员变量放进一个容器里,然后遍历访问这些成员变量。1 t' |; P) S- G
' @, l0 c+ D2 x; w5 L
完整例子 : P, z( }/ u. k$ C. a) mstruct C { int m; }; " L+ X4 U# C- Z- J# lint main() " K. \ j( a) d* `! w{" D+ F$ q; r( n) K: C, u% ~
int C::* p = &C::m; // pointer to data member m of class C ; c9 ~. h; i s' z9 S, i# k C c = {7};' } n. C; O9 R( _
std::cout << c.*p << '\n'; // prints 7# Z& a# }$ P0 ~* [$ }# V
C* cp = &c;# ]7 p$ T# u& J5 T6 T- J7 a
cp->m = 10;$ b1 W8 \: m& B5 J" ~7 B J, X
std::cout << cp->*p << '\n'; // prints 10 & I$ Y3 p% A5 X- p6 G7 q0 q! p* |6 v W% n; ~( [; p" G
————————————————6 ^+ J+ V' H9 h3 Z( {' q2 S
版权声明:本文为CSDN博主「南风fahaxiki」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。2 `, Q+ C. y' [& H+ d
原文链接:https://blog.csdn.net/m0_64407685/article/details/126788115 ) Q% t# N9 h6 t% S; H7 ^! s7 i- k* R/ ^/ c' @+ s