QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 2442|回复: 0
打印 上一主题 下一主题

C++数组指针、函数指针、成员函数指针

[复制链接]
字体大小: 正常 放大
杨利霞        

5273

主题

82

听众

17万

积分

  • TA的每日心情
    开心
    2021-8-11 17:59
  • 签到天数: 17 天

    [LV.4]偶尔看看III

    网络挑战赛参赛者

    网络挑战赛参赛者

    自我介绍
    本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。

    群组2018美赛大象算法课程

    群组2018美赛护航培训课程

    群组2019年 数学中国站长建

    群组2019年数据分析师课程

    群组2018年大象老师国赛优

    跳转到指定楼层
    1#
    发表于 2022-9-12 18:49 |只看该作者 |倒序浏览
    |招呼Ta 关注Ta
    C++数组指针、函数指针、成员函数指针4 }/ U- N" P) @/ c" @
    C++数组指针、函数指针、成员函数指针
    " ]8 J# K+ ?# c6 f3 ?  h" D; c& |7 |  |
    7 P% T+ M& H1 g9 l- `
    操作符名称1 x& h3 N& R" c2 L* m* r; s
    & 取地址符(Address-Of operator): w5 [  ?% c( S% \, f! I
    * 间接寻址运算符(Indirection operator)
    8 r" {9 E1 k, x& B.和-> 成员访问运算符(Member-Access operators),用于取对象的成员。
    . e# \: U# e+ ^: |* K# b8 y  a.*和->* 指向成员的指针运算符(Pointer-To-Member operators), 用于成员函数指针和成员变量指针的取对象。
    8 G/ }$ `: a- I: l8 g( D8 J- y8 F0 H() 函数调用运算符(Function-Call operator)8 L" ~4 W" F, ^  h' |$ \4 M: V
    :: 范围解析运算符(Scope-Resolution operator)* @/ N7 s. X0 J  ?4 K3 e
    如何定义一个指针变量
    6 k% n' M& Q8 x3 W假设类型T, 变量名称name, 指针的定义如下:3 x! S! M/ j# o7 U0 W- L
    & d0 u: n0 }& n5 c' Z- ]+ u! u
    T* name;/ z2 d0 E- ^7 E; }2 O% G
    标识变量名字name, 它是T类型的指针。例如' `* j* b/ ?' c7 }
    4 \# X  e: h. I3 r
    int n = 0;: u& S/ }9 l4 L2 F" \6 q* Q
    int* p_n = &n;) f5 z) k: y; o# @3 Z6 m5 b
    p_n是int指针类型, 指向某个int型的对象。
    5 W3 M/ R4 d! L6 H* ~0 c# n4 V+ T/ h5 X2 a8 M% ?5 t
    指针变量的修饰1 {: |! g: ~8 n. s# b' p' O0 v
    指针实际上也是一种变量类型, 只是它保存的内容有些特别, 是指定类型的地址值,通过间接寻址运算符(indirection operator)*, 可以访问到指针指向地址上的指定类型。3 e6 d# g3 Y; u1 _

    3 p" r; E6 X/ n7 [; {: P指针也可以用const, volatile修饰。 const int或int const均表示一个变量类型是int, 且该变量不能修改。以下两种写法都可以:( _  ?' [6 V# {" F4 f

    3 P, b; B, o2 \) p: Zconst int a = 1;
    ! e! \: N  P2 D( Qint const b = 2;
    4 {& D$ {/ P% e- `既然指针是也一种变量类型,同样支持被const修饰, 表示指针的值/指针的指向不允许修改, 指针所指向的那个变量是否允许修改, 那是另外修饰。写法如下:6 A' d% H' e1 V4 f

    0 V7 h2 _* b  \5 O" L7 tint a = 1;3 b$ T% I" b: C  Y  Y2 B
    int b = 2;
    / K; h  S: b: y; F  K. c7 Z9 Gint* const cp_a = &a; // 指针的修饰词,放在*号后面。6 i7 m$ N) X  q; j0 ^4 F  @; q6 m
    *cp_a = 10; // 指针指向的值可以修改
    4 h' E& C  M- d7 `( t: vcp_a = &b; // 指针不能被修改,报错!% p, q9 |% U# k3 i; m: Z5 B
    总结带修饰的指针的格式:
    * C& A1 d  v' G$ x0 {只要记住修饰词总是放在被修饰的内容后面。
    & o) S8 a' z2 O: T" X
    - G) b7 r1 b# n3 Q2 r! M5 h4 ecv表示const / volatile修饰词。指针定义形式如下:/ |# I# v* _- P
    # e, N" V3 v  m7 v1 Q, ?; G
    T [cv for T] * [cv for pointer] name& E6 ~. |' N+ g
    注意对T的修饰放在T的前面也是合法的写法。
    ' k* [: X) ?% F( X+ I- E) ]+ {' V
    / h  U% `% d% ?0 K- t: G6 q* Sconst int const c = 2;
    ! f4 ^+ C7 T* Q! s( P: C1 H在mscv编译器下也不会报错。
    3 Q  `8 U5 q0 U1 V' g1 O8 n% R. [. p
    7 T6 @( N1 p) U' g. x完整的格式:+ c4 l( U( {. F& f2 p- `
    [cv for T] T [cv for T] * [cv for pointer] name9 }# A  s) M  q+ S* @8 y  V2 R
      t7 B% A& A1 ^" T3 u2 C- n
    Syntax        meaning
    + O0 X$ b3 Y( N9 F- X$ ~const T*       
    % ?8 d- Z2 z4 b1 e) q- ^' gpointer to constant object
    % p8 {: Q9 ?$ M; G9 `8 ^% @: A" n4 G9 t7 y$ ~+ t$ a) ^0 {
    T const*        pointer to constant object' r% c# V2 d; [# {, k, q/ E$ V
    T* const        constant pointer to object1 P( w$ R/ W' g  s0 z# b
    const T* const        constant pointer to constant object" ?" E1 t7 C* H- O; V, B
    T const* const        constant pointer to constant object
    ; M* e( u3 v7 l# |! x4 k, Z上面格式中T还可以是一种指针, 指针的指针仍然是按照修饰词总是修饰前面的标识(T或者*)来确定修饰的意图。' A# r. Z5 E5 G( @1 v

    6 X( ~- g1 @* T5 iint a = 1;7 m, j3 `/ e5 l. H. E9 ]! }% a6 I
    int b = 2;$ D4 z* b2 }3 ]# Q: ^5 m
    " m" L) C0 t7 ]  J8 B6 B$ F
    int* p_a = &a;
    # N( J% N- H; N8 z1 u*p_a = 10; // 合法: U( X% K- E) c
    p_a = &b; //合法' {7 a  b* B( `( H
    ! `3 E+ g2 P. s) h. S, L! n1 E: P1 K
    const int* cp_a = &a; // const修饰int类型, 并非修饰指针
    6 G( H3 Z" D3 z*cp_a = 11; //报错! const int类型不能修改
    ' }+ c0 o4 |( K! E- ]# pcp_a = &b; // 合法, 指针没有const修饰,指针可以修改。
    6 W+ U  O# P: t& [1 E; m3 c/ G2 o) `- p7 R! e" P5 w
    int* const pc_a = &a; // const修饰指针。类型没有const修饰
      \- L& B, j  B; s8 d% q*pc_a = 12; // 合法, 因为类型没有const修饰,可以修改。
    ; D: m6 S7 ]4 @0 a2 w3 o5 n$ Tpc_a = &b; //报错! 指针被const修饰, 不能修改指针。3 T- D# R0 }, ^

    ' _+ s* P3 s, D9 _int const* const cpc_a = &a; // int类型被它后面的const修饰, 指针符号*后面也有const修饰
    * C  b4 `0 \7 [*cpc_a = 13; // 报错! 类型被const修饰,不能修改。% g& w; {  R8 i& x) C5 Z
    cpc_a = &b; // 报错! 指针被const修饰,不能修改。
    4 C. B! O- j, r0 H$ ]0 |# |
    7 Y+ r4 C  ^% a/ W2 p9 w! s* a 更复杂的指针的指针6 N/ P2 B: ~2 E9 \  F5 d
    0 \+ `! L" g- d. O; Q
    int a = 1;( L- I: Z0 E  U- I5 [: d- N
    int b = 2;* C5 h  Y1 O0 D# {$ G  R
    int* p1 = &a;' I6 j0 N8 p7 B, k
    int* p2 = &b;0 Y" h0 t* q9 Z
    const int* ct_p1 = &a; // ct for const type
      W& [3 t- e/ M/ F3 v: Qconst int* ct_p2 = &b; // ct for const type; Q$ a4 v9 k" i: y

    5 L5 U% M5 R& H% i! n// int * * pp1; 指向(int*)类型的指针: V2 ?% Q6 S2 _( U/ [; K! t' [
    int** pp1 = &p1;  
    5 y% W6 e8 G1 Spp1 = &p2; // 合法, 5 `) [; @) [6 m$ L/ X. W
    pp1 = &ct_p1; // 报错! 类型不匹配。 (int*)不能指向(const int*)
    5 ]) `. w8 F6 b+ G
    . A  U& G0 }0 Z  u# r+ {// (const int) * * pp1; 指向((const int) *)类型的指针
    ! s  w- G# g& I7 ~8 w% p' oconst int** ct_pp1 = &ct_p1;  ! \( Q# o6 _) f
    ct_pp1 = &ct_p2; // 合法. ~6 z% l1 R+ {, o$ g
    ct_pp1 = &p1; // 合法!(const int*) 可以指向(int*)类型。
    2 W" J8 a+ K6 f2 g, y; z$ F" m& F% D: N( Z& N7 M3 F  ^
    // (const int) (*const)
    0 k( ]* e* T$ X# |* Q# S& |! \' f( Y) Lconst int * const ct_cp1 = &a; // 指针也不能修改: Z" V+ o0 p# m( `
    const int * const ct_cp2 = &b; // 指针也不能修改/ I! o& {  D1 U7 ~
    ct_cp1 = &b; // 报错!指针有const修饰& C! T3 V! e, L# g

      \* ^3 n5 [" R; i* j// (const int) (* const) *  指向((const int) (*const))的指针
    ! p. ^7 o" s% u% M3 Fconst int* const * ct_cp_p1 = &ct_p1;  / m; n; U3 @: W" `7 `! k) ?( b
    ct_cp_p1 = &ct_cp2; // 合法, 指针的指针并没有const修饰, 指向的指针有const修饰
    1 J% T1 H/ R! e$ o* y( R2 i5 c*ct_cp_p1 = &a; // 报错!等价于操作ct_cp2,  指向的指针是带const修饰的不能修改
    " o( h) w( w: I( Y8 z: ~( Y. q/ y% M" U6 h$ K  C9 Y. M% J  i0 S
    // (const int) (* const) (*const)  
    4 T$ i8 ~. e1 Z$ l! V// 指向((const int) (*const))的指针,且该指针被const修饰
    0 R0 \! V& h5 H. [; c+ Nconst int* const * const ct_cp_cp1 = &ct_cp1;
    ! N) d8 _- r  G& f' Rct_cp_cp1 = &ct_cp2; // 报错! 指针的指针被const修饰, 不能修改指针指向。& {7 z& r; |/ k" [

    8 Y  _7 l$ \% {' H+ F6 z一行声明多个变量
    3 }: J, S) m% g! m7 \( y类型 + 名称定义一个变量。
    ! K8 I- _0 v/ W变量的前面可以加*号修饰, 表示指针, 一个星号代表一层间接。**表示指针的指针。
      s7 X0 E+ s  y
    ' t2 x) F! k8 G2 q* b+ @8 d# x& ?5 Qint a, *b, *c, d, **e;
    3 @& C3 t+ B  Y4 {$ R& j* Za = 0;: x4 n0 j# L2 B8 z; G8 v
    d = 1;6 p1 w$ V7 N' E  V# @7 |$ y9 [0 N
    b = &a;
    ; W/ a0 p6 e+ I: r. ^& Z, D% V, Nc = &d;8 H7 L( V/ p7 H3 n1 q0 P9 o
    e = &b; // e为int**类型 指针的指针6 [4 v4 E# A! M, g! Y' A
    e = &c; // e为int**类型 指针的指针* g; V: v. i6 a0 q
    也可以用括号包围变量和*号。
    ( d' q, n7 i, Q4 J) h4 E% c/ r# f" x; c* y8 p' S3 p4 V5 \/ }7 \3 F
    int (a), (*b), (*c), (d), (**e); // 合法定义。) }0 B) G  `! Y5 h/ g( y
    括号可以省略,某些情况, 个人感觉加上括号更清晰一些。例如; s7 e& ^, w6 i" }3 R2 h
    * b6 U4 G- S2 E; l- D  i% ]! h2 J
    int (a), (const *b), (*const c) = &a, (const d), (const* const* const e) = &c;! h% P9 h# M6 F4 h; H  ]
    写成; E, R8 R/ m- `" x
    7 |( g( P6 e8 ^  j8 @
    int a, const *b, *const c = &a, const d, const* const* const e = &c;
    8 C, G' D& J% {& K% }* Q, D更重要的是, 后面我们表达数组指针,以及函数指针时,括号是不可缺少的, 带括号的表达更加统一。
    3 ^# n: h2 R1 P( @' |0 a& L" g
    1 b2 K# O% ~+ L- }/ A% d数组指针5 F3 k: f4 I* D) C' t
    数组基本表达5 E) O4 z  k1 ^) B3 u% n* {* G# T
    int a[10];  // 定义了类型是int, 元素个数是10的一个数组。
    . i9 j/ G7 f( j$ {0 Y3 N6 a! C由于c++要支持一行定义一个类型的多个变量。 所以数组的[]时放在名称后面的。虽然我觉得9 A+ d, O9 j% M" s
    : K% L/ x& `8 J, L7 l; M
    int[10] a;9 z6 ^( u+ d& s5 R
    这样的写法更符合类型 名称的思维, 但是如果类型都这么写的话, 没法兼容以下的写法:% u1 Y6 B: j& }/ z6 c2 I% q

    5 Q+ M2 ^! u6 U. z/ M! cint a = 0, *b = nullptr, c[20], **d = nullptr;* w$ C& c# c2 c
    c++标准规定如此,但我们可以通过每一行只定义一个变量的写法, 类型会更加清晰。9 m4 i% J2 }0 L5 |' D

    - A4 H( K; T+ z0 [int a = 0;
    2 M2 c6 |' ^; D+ W2 p5 bint* b = nullptr; // 指针int*1 Z; R1 b4 S( a( j8 q1 s3 W' u4 D: m9 @
    int c[20];2 H* b4 k& e* I. v2 N0 b6 |5 ^
    int** d = nullptr; // 指针的指针int**
    - M$ n* Z- f8 e0 x4 J数组的名称是什么类型
    ( B: \3 A% |6 b: W2 d数组元素类型的指针,可以直接指向数组。 并且数组跟指针一样,可以通过下标去访问元素。
    % C- v2 S" p* b+ F7 F8 T* c: Y- B, z& @" }
    int a[10];2 M. j- q& z: d/ r4 U, p
    int* p = a; // 指向a数组的第一个元素7 c. I2 h2 w0 u1 ~9 e* a
    a[1] = 1;
    8 J6 E& [* u* ?  Up[1] = 1; // 效果与a[1] = 1一样。
    . l2 }+ h, ?( n; ?! z* _数组可以当作T* const来使用, 但是又与T* const有些不同。sizeof()的结果不一样。
    0 e" D& I; w% l5 K. j5 _: \2 A# b- g3 [0 ^  i) f5 h
    int a[10];
    , z# `' b' F  Y- P5 P' J. Xint b[10];9 [9 {0 t0 [7 G
    int* const p_a = a;4 g+ X# {( V0 B" n
    a[0] = 1; // 合法。 数组的元素可以修改。
    6 \- Z& S* i- c5 H+ u, Pp_a[0] = 1; // 效果与a[0] = 1一样。
    9 |' t9 P7 w5 Q1 E6 ~
    3 z, r* t: t& [' v1 }% H) C. Va = b; // 报错! 数组本身的指向不能修改。- n4 x3 C2 ~) c, u
    7 {' b2 {$ O/ @3 R- }8 |
    // 所以数组a可以当作int* const来使用
    / Q! d* n+ Z0 L" z; f: I9 o( }9 Jint *const& ref1 = a; //正确。
    1 D& b1 |8 Y7 h; N9 Dint *& ref2 = a; // 报错!
      M/ K* _/ N! ^# y$ @" x  a1 A" J9 `" e( ?. @# ?; o0 Z4 q4 r2 s
    // 但是又跟int* const有些区别。: r  b" x( `* L6 t; `
    assert(sizeof(p_a) == 4); // 32bit程序。0 t' c/ ?, U1 O: o
    assert(sizeof(a) == 4*10); // 32bit程序
    5 i; k. r. V) e, E
    . C# f  e' w' R# h8 S数组跟元素指针的作用很相似,都可以通过下标去访问元素, 但调用sizeof()函数的结果不一样。元素指针的sizeof()返回值是4(32-bit应用)或者8(64-bit应用), 数组的sizeof()返回值是数组实际占用的空间。数组可以当作指向第一个元素地址的T* const来用其实就是我们常说的数组到指针的隐式转换。当数组作为函数参数传递后,会自动退化成T* const, 在被调用的函数内部调用sizeof()的返回值跟T* const指针大小一样。 数组传递作为函数参数后, 在被调用函数的内部与T* const是没有任何区别,只有在数组定义的可见范围内sizeof()才有获取数组占用空间大小的效果。' U" H- y+ H- V  f' ?3 P: r
    0 G* Q" u; ?7 U, {) D; f
    以下3个函数翻译成汇编以后,汇编代码是一样的。
    8 x5 n7 A9 P; `8 p
    3 h" `& R& h+ }void Func1(int* p_ary)
    5 L  C2 K* m' G5 ]# w) p{
    - }% ]5 Q& B/ q, F; F: G    assert(sizeof(p_ary) == 4); // 32-bit6 U/ [$ ]* z7 O' a
        p_ary[1] = 1;
    8 b$ J7 J  X6 E; O: X' |}  O5 }. m1 a3 Q$ [8 F) h' ~2 m

    : c" a/ k! l* avoid Func2(int ary[])
    ( P& `' F; H% D/ @, d9 e- {{
    & n! D) v3 m, N+ m0 D' ?. m    assert(sizeof(ary) == 4); // 32-bit
    7 m) k3 b% U# K4 r9 z. p    ary[1] = 1;  C( F, Z/ x9 v, }0 J* i) e. I
    }& [- _& R5 o  t9 Z3 o
    ( W( s/ f0 A5 u- ?% i% b
    void Func3(int ary[10])$ {& A- w: `8 N' D! v% J! l
    {
    ; O; a! S* @: T    assert(sizeof(ary) == 4); // 32-bit
    + H$ q7 B! y3 `& s) }5 Q- D: u    ary[1] = 1;2 J* \1 c( N* T* i8 s# t/ l
    }5 Y8 i! R" _+ \9 C: @$ I/ S
    % w4 e; _) j( B* v7 ~, H
    int main(int argc, char** argv)* ~/ z. z! w  L. ?4 b, i, V
    {4 X; j' ~2 L4 g# C- N+ j8 \, U
        int a[10];
    + |! p' v1 t4 {* W2 ^  d* [6 w% A    int b[20];
    0 l* M, i6 x/ G, }- i& ~5 @( t    Func1(a);& Z" W2 I( {6 w+ ?5 X8 S2 Z6 j
        Func2(a);1 N7 K: }* s0 Q9 m0 r8 ]* D
        Func3(a);" y5 ]8 f$ ]4 X3 R
        Func3(b); // 退化成int* const了, 即使数组长度不匹配也不会报错。
    " _  t! J! L* S& q6 C2 D. q% k, m! f    return 0;7 x/ h; L- _$ k$ e' i
    }
    # j0 l' _2 V% @5 b: K% j3 _0 q* w4 j7 T6 G8 y! m

    8 ~* K3 v' g' O" e; s/ ?8 ^# S. G8 r! `  A4 n  u  I% W( d. t
    多维数组6 w9 {' L: V. \) M, _
    一个3行,4列的数组, 结构如下:2 l' K2 j2 M6 E  o1 `( L! O- _

    3 b+ l: t# t( i7 f- y/ X' T5 nint a[3][4];# [8 L: g! B# g7 k& m7 [& F
    column 0        column 1        column 2        column 3
    ) Y, k' L, J& Z5 g0 Srow 0        a[0][0]        a[0][1]        a[0][2]        a[0][3]
    . K5 G+ H/ ~$ a) Brow 1        a[1][0]        a[1][1]        a[1][2]        a[1][3]" s9 i2 H8 P0 l1 X- V( `
    row 2        a[2][0]        a[2][1]        a[2][2]        a[2][3]& L' B/ v9 X5 Y. i* ^4 ~) r) V
    数组初始化
    9 c9 B+ s/ O  A/ ~7 }: `$ x5 G2 \7 |: m& F# Y, H0 R
    int a[3][4] = {% o: @1 }9 E4 `; L# w  k/ J3 C
        {0, 1, 2, 3},
    ; |8 ?7 T6 r3 f9 g; T    {4, 5, 6, 7},- L4 m: v! Z6 K& q0 l3 i% h
        {8, 9, 10, 11}
    7 p7 L* j: U3 o% E: l7 K, C6 Z' _};
    0 e# c" m( u4 H* { 实际上多维数组和1维数组在开启速度优化后,翻译成汇编代码是一样的。/ E% ~% `0 V9 p& g4 x
    " d0 ?. x% o6 J3 t! T: F% W- [' `
    void Print(int* p_ary);
    ! ]# V& J1 X( G& W& P& A! f( z. m4 B6 P
    void Test1()3 t7 O: P; ^: N* ^$ _7 l) ~
    {0 p& y" S9 {- o2 l
        int a[10];" T  @2 X: F6 b% M6 X
        a[3] = 3;7 B! z# p% y+ L/ t% ^3 w0 @
        a[7] = 7;
    7 a  v# C' I& K; \6 Q. [    Print(&a[0]);) g$ ~3 U6 q6 z' s( x
    }
    8 v0 E2 v6 Q# Q
    $ a, F+ N* v3 F" s& S" f( C- O: R( Xvoid Test2()
    ' ~0 X! r& |6 o( c* K. N3 j/ r+ M{6 \. ^4 U+ o( M/ ^
        int a[2][5];
    ) A$ r4 X. ]2 q& m" ?    a[0][3] = 3;
    4 ?8 A2 p6 A# k' \( }! J- O    a[1][2] = 7;8 d1 s! W" {8 A" o: `& P/ R
        Print(&a[0][0]);
    2 B' G/ j; V5 Q! @" z}
    " T& W  ?# p1 A+ T* u* W/ |( q! l* S& E

    " h. H" l5 f; O' G& _' [4 |" }( ^$ G7 t
    很自然地,多维数组也支持用1维数组的方式去初始化。8 X( F; k: p! T+ H) N2 G9 K
    0 F+ [/ o& k3 A; Q0 s6 M  W/ v
    int a[3][4] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };9 u! ]' s# M5 y( D9 z" @+ }
    既然多维数组与1维数组没什么区别, 为什么还需要多维数组?
    9 L* Q; U. o0 P# t7 @9 Y6 }5 c5 {& p" p: E. D9 P
    假设有一幅RGB图像720*576个像素,每个像素有RGB三个通道,每个通道的值是8bit大小。给出图像的首地址p_rgb_image, 我们要取第40行,第50个像素的R,G,B值。代码如下:
    3 G' D6 P) u6 C2 k1 a, e7 L+ q
      o0 f, q7 y6 ~- O+ s5 Vunsigned char* p_rgb_image;
      Y& M# |5 k* a" H/ W  M  z* Bunsigned char r = p_rgb_image[40*720*3 + 50 + 0];
    ! c8 H( L' L% o* g% _! punsigned char g = p_rgb_image[40*720*3 + 50 + 1];, d' \4 h) A. d6 t: A
    unsigned char b = p_rgb_image[40*720*3 + 50 + 2];
    & u3 b/ @5 x: S* G$ W类似这样的场景, 采用多维数组的写法, 有点类似以索引为参数,可读性更高。相当于程序员和编译器打了一个配合。
    & N: a; p3 c. ]6 D* P- ~: j  p
    9 B( ], I- F4 y- Z' P3 k' |enum# z; M# x8 M. A: u5 f( |, o
    {
    " D4 X) l7 l, f* Q7 T2 p% |- v Red = 0,
    % A, O7 }) h# j/ j1 o0 D Green = 1,2 D5 B! O4 h( x% @8 q% D
    Blue = 2& o6 n2 x: d% R3 G
    };% H3 ?5 B8 W0 e' c
    unsigned char rgb_image[576][720][3];
    ! z$ Z* h! C+ q' }+ j5 a  L( Tint row = 40;* G# Z% a9 _1 O
    int col = 50;
    3 A4 @/ u' M' U8 ?! S4 ]  ^unsigned char r = rgb_image[row][col][Red];
    & z2 n) T+ t  A3 b$ tunsigned char g = rgb_image[row][col][Green];
    $ z+ H; }  I2 }! iunsigned char b = rgb_image[row][col][Blue];
    5 M1 E4 R: R* j6 {5 @7 ^% u数组指针以及与指针数组的区别2 J$ |$ h: y* p- X4 S" \# b
    数组指针,是一个指针, 指向的对象是数组。 数组指针的赋值,要求数组的长度匹配,否则会报错。当指向1维数组时, 需用用*取得数组对象的引用,再用下标来访问数组元素。! T# P( U( W* Y) g) k( V
    指针数组,是一个数组, 数组保存的元素的类型是指针。; D. s- N) p$ p3 x$ R8 i9 ~
    数组指针的定义/ c1 X$ G! e/ o  T  V5 x
    数组指针定义先定义一个数组。3 w) s  m" w0 r2 w( Z' f
    int a[10];  l  I& b9 J0 F% g2 ]6 O, J
    然后对数组里的名称用括号括起来后再在变量名称前面加个*号
    # V6 o/ \- s, v$ m7 e2 q' \int (*a)[10];# ^$ {8 M/ @0 w# |% i( J3 l
    后面你会发现函数指针定义类似。
    / ]% x2 \* E' j; u- ?2 S: k// 各类定义对比. ]$ _, l( @; \! C
    int a, *b, **c, d[10], e[10][20], *f[10], (*g)[10], *(*h)[10];: T( \5 J6 w, L1 @
    ( U* x3 h1 F' h+ T9 s  F! L  W
    int *f[10]; // 指针数组, f是包含10个元素的数组, 数组里每一个元素的类型都是int*8 @  R' T$ q0 I% k) H9 n8 B/ }
    int *(f2[10]); // 指针数组。另外一种定义方式。
    0 {; Q7 s2 J# X' m- ]1 |$ Tint(*f3[10]); // 指针数组。另外一种定义方式。
    + |5 x# t8 @2 o! _4 Uint(f4)[10]; // int数组5 C( H2 h' W. q& M
    int(*g)[10]; // 数组指针, g是一个指针, 这个指针可以指向类型是int,元素个数是10的数组) ?7 o' a6 C; K  m$ z
    int* (*h)[10]; // 数组指针, h是一个指针, 这个指针可以指向类型是int*,元素个数是10的指针数组
    . V3 X( H5 o! I9 P9 r# q- F+ J
    : w) x: ^; p, D* y& V# Rint d[10];# G) m9 J+ K) F8 s/ q. L
    g = &d;, O; J$ G2 B8 q- ~& {

    . G3 y7 |8 L2 H; Y2 @' ~: _int* e[10];
    6 o3 `' f& r7 N$ j% A# A+ H2 l  Jh = &e;- |6 F* ^6 Z: p' I" v& [+ T; s6 a
    数组指针的使用
    6 R' d) u1 R7 t: G- u9 U+ ^" i数组指针一般先通过*号取得指针指向的数组对象, 然后再用下标操作访问元素。
    + f3 ~5 b. T3 c# {# G) v5 ~7 f- T# ?- b( w% ^5 [& [. p
    int a[10];9 ^2 }  m) A# b! Y2 z" y
    int(*p_ary)[10] = &a; // p_ary是一个指针, 指向"int (*)[10]"类型的数组& W; b$ R0 w3 n
    for (int i = 0; i < 10; i++) {5 k3 e. S# c# A' m" c
    // p_ary是一个指向数组的指针, 需要先通过间接寻址运算符*(indirection operator)取得数组对象
    # }8 u/ w2 R" h& i: L // 再通过下标操作访问元素。, I* t) ?) ^) {( d4 C9 K
    (*p_ary) = i;
      ^6 A' I$ V, y& O+ S9 x; w6 Q; `; F; V}9 K5 \9 \1 H5 ]
    - p, e) l$ h0 ^2 `9 U
    int b[10];. ~8 y& c' A& |' e( C! V
    int c[20];
    + z+ _! C1 R- u: F$ Tp_ary = &b; // 合法7 ~7 d* X5 [1 W" C+ G/ f
    p_ary = &c; // 报错! 不能将 "int (*)[20]" 类型的值分配到 "int (*)[10]" 类型的实体1 A! K2 m! Z( Y9 I4 O% d, L8 r0 j
    数组指针指向多维数组的子数组3 ~7 R( s. }8 r( Y9 R
    int a[10];
    5 u- x! Q( ~, B) g- pint b[4][10];
    : |! {# }: z- tint(*p_ary)[10] = &a;
    % ^- S% V: O; \for (int i = 0; i < 10; i++) {  o7 \! X% A+ u* @1 \' g
    (*p_ary) = 1; ( G/ B3 h6 W8 ~
    }) e1 x  }7 w2 g$ t4 d3 f. r1 B
    ) e: F1 j) U+ y9 _, b' L% ^: {+ ~# M
    p_ary = &b[2]; // 多维数组,可以看作数组的数组,# g( \1 `. P, U' ?7 I
    // b[2][0] ~ b[2][9]的值都被改成2了
    / e$ l: [5 c1 `' Vfor (int i = 0; i < 10; i++) {% w& A5 v( L$ i- j8 \* C
    (*p_ary) = 2;* G( Q! j2 T6 O
    }
    4 x: m# [3 L6 |. a, x多维数组指针# M+ J# G- \  r; C
    多维数组指针,是一种指针,指向的对象是个多维数组,支持多个下标操作。
    6 e6 A2 h  T% m8 P2 e% y' `! {9 y0 V1 @( N; ^8 F
    int a[2][5][10];+ e& s% D$ u, g8 |. Q
    int(*p_ary1)[10] = &a[1][2]; // 1维数组指针
    ' Q) N, ]% `3 \5 [/ L4 V/ eint(*p_ary2)[5][10] = &a[1]; // 2维数组指针
    " q7 G# z0 G1 I% ufor (int row = 0; row < 5; row++) {* _! q5 ~  K8 ^3 Q4 w8 x
        for (int col = 0; col < 10; col++) {: [  _! H9 F0 B1 j
            (*p_ary2)[row][col] = row * col;. M8 ]8 {& n1 C: u
        }
    6 \& l2 M2 v, t0 M; g  P; E5 s" ^}
    + B, o& M- H; ~数组指针和指针数组对比实例7 Z( z' q: L: e. @3 \- O. \; x' W
    数组指针还是记住两步法即可9 F1 f4 E, e8 s( e& K2 Z4 y% ], f
    5 y/ [/ w) M, E! D" O) q
    定义一个数组- i% H* }9 R1 \& w- ~
    括号包围1中定义的名称,再在名称前加个*号。
    6 `9 ~7 k- K0 Hint a[10];
    + t4 I6 \2 g- W2 \2 b, g( Oint(*ary_pointer1)[10] = &a; // 数组指针
    : D$ {! t# I& n; zint* pointer_ary1[10]; // 指针数组。元素类型是int*
    ! u3 e  a2 F& Rint *(ponter_ary2[10]); // 指针数组。另外一种定义方式。
    3 W3 h5 F$ E* m+ \2 m9 Z: m, z2 O" @int (*ponter_ary3[10]); // 指针数组。另外一种定义方式。4 s0 ?) ^: U, N& @% ?+ X; j$ `$ M
    int c, *d, (*ary_pointer2)[10], *pointer_ary3[10]; // 排列定义比较。% ~* ?1 k) o. ?0 {& I6 z

    3 h+ G" W, O7 z" k! X// 指针数组可以把每个元素指向数组对应位置的地址。2 u6 F  ^5 b; m* H2 E/ ^& F
    // 这样遍历指针数组, 可以达到遍历数组元素的效果,但是注意每个元素都是指针,
    # Q" m+ y, \' E// 需要访问原数组的值的话, 需要对指针用*间接寻址运算符。
    ; d& U: o! t& p4 _( l7 Bint* pointer_ary[10];
    ) j" P$ V3 d! Z9 l) A. Nfor (int i = 0; i < 10; i++) {. ]' {" b7 m# l; c/ g
        pointer_ary = &a;  J9 }  C+ z5 D# Y
    }, s0 Z" \- L$ c2 S1 [( N) }
    // 类似遍历原数组效果。7 y$ n* s/ S  X- \. A# Z
    for (int i = 0; i < 10; i++) {/ u3 \9 V, {3 \$ g' U0 Y( `
        *pointer_ary = i; // 修改原数组。' H3 G6 H" A% U* L" Y. m( ^
    }, o* r9 M& A& V- F% }" i. Q

    ; X  E4 Y+ f5 s8 ]7 F/ y函数指针
    1 O# R, s! s8 H/ d7 L9 L/ e) N取得函数地址
    1 J- _! N) b/ I+ b5 M) g5 M5 X函数的名称作为参数被传递时,会隐式转换成函数指针, 和在函数名称前加取地址符&等价。建议带上更加统一和清晰。4 g6 t& ~0 I' Z1 \

    3 k/ F8 c" D6 K$ ?& U) svoid f(int);
    2 b6 v& j' q9 _3 d4 ]* _int main()# F( H$ g7 r5 |) @( U) ^8 D
    {
    ' P5 `: Z- @: S4 D7 H    void (*p1)(int) = &f;
    $ [" y, t/ q; L( h) R2 H  J    void (*p2)(int) = f; // same as &f
    / _# f$ f% g5 ~4 U- L# {$ d    return 0;# {5 S% k4 n0 I; }; h4 ]
    }6 v: a$ Q, C) B1 j) W
    翻译成汇编代码, p1和p2的赋值是一样的。3 Q1 L. b' h- f8 {6 I

    # G1 Z; f; i! N7 t3 P# Q( I3 X) T- t+ W3 c  D% q' C7 C
    8 ^! b; Z( {: z# J: |8 T4 U
    函数指针的声明
    ' A1 O- o9 L0 E4 B2 D' M单个函数指针变量定义步骤
    3 Q" v- [# g0 D8 L: j- c定义一个函数。void fun1(int a, int b); int fun2(double a);/ U9 |) ]# n& p) d& u( k
    用括号把函数名称包围起来,然后在名称前面加*号。void (*fun1)(int a, int b); int (*fun2)(double a);
    4 n7 ^% j& h6 \. {. p0 ~% T如果要定义函数指针数组,在定义单个函数指针的基础上,在名称后面加上[数组长度]void (*fun1[2])(int a, int b); int (*fun2[10])(double a);9 @# Z7 G0 r0 r$ F' G7 H
    typedef定义函数指针
    " }, @! a' P2 p5 D/ m, `5 o可读性高比单个定义要高,特别是声明多个同类型的函数指针,或者函数指针数组。9 b; W" t5 A3 v# f1 p' X* s

    ' O( |* k8 v0 \4 y2 e, Gtypedef定义函数指针的语法
    ) I* T) q% M! n7 J' {  S4 Z; C3 utypedef有两种做法, 一种就是定义一种函数对象,另外一种就是定义函数指针。用法稍稍不同,效果是一样。其中函数对象不支持赋值, 但是支持引用。0 P5 j* `, Y& q: r
    8 w0 X9 [; x* P- H% K7 s" R2 p' J
    typedef int FuncObject(int a, int b); // FuncObject类型是函数对象/ c6 O' S2 h% T% A- v1 E
    typedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针# ~0 W, ~7 I# p) G5 Y. G- E. b; @
    FuncObject* f1 = &Add;
    7 r  K( p7 M0 x! _$ R1 gFuncPointer f2;
    . y" W  E# i- v: R) \  pf2 = f1; // f1, f2类型一样, 都是形式为int(int, int)的函数的指针。
    . u) f1 {( |* R0 G$ V+ vFuncObject f3 = Add; // 报错! 函数对象不支持拷贝
    9 {2 ?! R6 d9 e* s- v2 x  c1 AFuncObject f4 = &Add; // 报错!&Add是函数指针,与函数对象类型不匹配
    5 d" s  V' |+ N2 |, X5 h6 iFuncObject& f5 = Add; // 正确/ W4 I; ]5 e2 H9 n$ U
    int ret = f5(2, 3); // 正确! i& \" m: F' m( y3 N9 I9 @
    FuncObject& f6 = &Add; // 报错!&Add是函数指针,与函数对象引用类型不匹配! G2 [  A9 ?( Y1 A4 W* ~8 Z' G0 {. m
    如何记住typedef定义函数指针的步骤
    1 p: C+ V! N* v% W  v" U像定义一个函数指针那样, 指定一个名称。int (*CalFun)(int a, int b);5 r0 s' V( j) W  F: f$ |
    在这个函数指针变量声明前面加上typedef。typedef int (*CalFun)(int a, int b);' Q$ ?( E' R5 F$ p8 x
    完整例子
    & `/ n7 a) f2 z" b& qtypedef int(*CalFun)(int a, int b);
    / m! \, M- z0 [6 O, w4 i8 t9 ~4 b$ S4 E4 B. C
    int Add(int a, int b)
    5 ~( p' T# P  a4 I# Z% s{/ O; W6 m5 C: J/ }
        return (a + b);) c! W* E9 V9 i  I  c. K+ \1 r
    }  N# \! ?3 [  b, v  k# p

    , ?' A) U: X' ~int Sub(int a, int b)
    " Y+ v1 `' f) r2 ^3 X) J1 D{6 Q$ V# m) ?$ t1 ^6 f3 |
        return (a - b);" V! Z9 Z6 F0 M
    }
    2 ~/ m8 p% V1 L8 O6 U; p
    ) [& m' k* P' Sint main(int argc, char** argv)2 b/ K9 T; [3 k6 N9 p  o2 `9 b/ G' j
    {
    ! K, j- W3 ~1 z! S    CalFun f1 = Add;$ o3 J  {, t: M% ^+ E+ O
        CalFun f2 = Sub;
    8 ?' Q9 A( _% i3 {8 c0 ^; W    int a = f1(2, 3);. g- x3 B* O+ d9 v5 W9 ~1 X
        int b = f2(10, 5);) x* w0 W% p; L# U2 u

    9 |# B/ m. N7 W& O& W/ f- n; t    // typedef定义的函数指针数组。5 ?0 t5 I  p8 e9 Z* E
        CalFun f_ary[2];
    ! e# o3 `. V3 y5 L1 j! E    f_ary[0] = Add;; h: ?( P1 T0 |9 W
        f_ary[1] = Sub;: |* W& {- X- k

    0 ^5 b) c4 a6 A: q( N    // 单个定义的函数指针数组。
    + Q3 |0 }6 X! R3 o& D/ ^+ H    int(*f_ary2[2])(int a, int b);
    0 i) u; A0 J3 w' E) W, G    f_ary2[0] = Add;: \' }! d0 V; P6 o
        f_ary2[1] = Sub;
      Z7 V4 s1 m" W4 k7 [. A5 g' r! b' z
        return 0;8 f* r& w# f. N) Z/ b+ W9 ~
    }+ y9 D: B9 a' `' A. @

    ' x1 \( L+ i; J0 eusing别名定义函数指针
    3 m. b2 z( d2 s( ~$ l6 F, ec++11以后的类型别名定义--using也可以用于定义函数指针, typedef的好处它都有,个人感觉比typedef更直观。using类型别名同样分函数对象和函数指针两种方式。
    + H! H: b. `. G; d. ?! ~  [
    ; j2 t/ V9 k2 E8 otypedef int FuncObject(int a, int b); // FuncObject类型是函数对象1 R# J% T8 U$ D8 f6 C4 v
    using FuncObject = int(int a, int b);
    # f5 i0 N2 Q6 R  _+ R5 J- ytypedef int (*FuncPointer)(int a, int b); // FuncPointer类型是函数指针1 m, Z! c$ M- M3 m0 s# f4 ?( }
    using FuncPointer = int(*)(int a, int b);1 l+ X: W$ O8 T3 j, I' E' N* {
    函数指针的调用  y3 \) m7 Y1 Z% @. B
    函数指针和函数对象都可以直接后加括号调用
    5 T% w" v) Z+ E5 T2 S# Fint f();
    + I. _$ u4 k. i5 Nint (*p)() = f;  // pointer p is pointing to f
    ' `9 }- Q( I. e1 yint (&r)() = *p; // the lvalue that identifies f is bound to a reference
    5 B* ]3 F0 B; P5 Wr();             // function f invoked through lvalue reference: y+ Y8 n; W+ i, ?
    (*p)();          // function f invoked through the function lvalue; D# F- W+ J( O1 y/ b6 ~
    p();             // function f invoked directly through the pointer5 [4 A5 ]% O6 u6 e* R, m
    如果函数有重载, 函数指针会指向匹配的那个版本。
    + k; ~2 @; o2 j% E4 g; k6 atemplate<typename T>8 f$ u* K: r  B  x( H: m
    T f(T n) { return n; }
    : b0 x1 ^: `6 h0 f
    2 ]0 \( Z& d. ^7 i- \* edouble f(double n) { return n; }
    6 \" Z1 u5 P7 a+ m! \) }& l- s
      ^+ K4 r+ m4 @) H, Z: O  bint main()
    # Y7 X0 D+ }( r{1 Y& i) y2 G% B% W
        int (*p)(int) = f; // instantiates and selects f<int>
    ! z! a; j* B! y* G2 _}
    7 e4 W! V) t  M成员函数指针9 D% `$ L# u6 p4 P
    静态成员函数,除了增加了访问控制以外,跟普通的函数指针没什么区别,所以普通函数指针可以直接指向类的静态成员函数。但非静态的成员函数与普通函数指针不太一样,声明时需要指定函数归属的类名,并且调用需要指定对象实例。% v* |; u+ i) p. g) k

    0 d# B2 c" u: q. V3 h成员函数指针定义。0 Y  }# A! Q! U6 Y
    像定义类成员函数实现那样写, 并任意指定名称,这里作func。void ClassName::func(int);& i3 G: H! ^% |1 }" S. j7 \
    括号把类名、范围解析运算符::、名称包围起来。void (ClassName::func)(int);
    % t6 |% q- L- V; ~- r4 o1 J在名称的前面加个*号void (ClassName::*func)(int);
    0 s$ I1 L) A' L( A成员函数也支持typedef和using的定义方式。typedef void(C::* MemberFunc)(int); using MemberFunc = void(C::*)(int);
    6 a5 M  ~2 T( L( d成员函数指针如何调用。) ?# I0 y; O/ a# {0 [  @& C
    假设成员函数指针名字为func
    : X% D) k5 r& `  o2 ]( |" @. q/ u* ^
    void (ClassName::*func)(int);4 T/ G* v, G8 `9 ~! ]
    对象式调用。' J! Q+ m" q( W; ?; A5 {
    ClassName c; // 被调用的对象" A& e7 {2 }' P0 m1 a; G; l: y5 w( E
    成员函数指针名字当作正常函数那样写。6 c7 `; v! @: B  I" _1 |
    c.func(3);
    ! a% f# l( W1 b$ [+ Z: q2 d成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。/ Y  j' i6 M. N3 E7 i2 d
    c.*func(3);2 W8 a0 {5 Q0 n: g5 Y+ k& X
    最后用括号把调用对象、成员访问运算符.、间接寻址运算符*、和成员函数指针的名称包围起来。
    " L0 @7 ^4 }) }. d(c.*func)(3);. U1 ~7 F  E# J7 ]
    为何要加上括号? 根据c++的优先级标准,取成员运算符. > 函数调用() > 间接引用符*。 *号优先级比函数调用要低, 成员函数指针还没取得对象就被调用了,自然报错。 另外" J0 m5 s/ U1 C3 T& x
    (c.(*func))(3);
      v) H) R! c' i这样的写法也不行。 .*和->*是整体作为一个运算符的,中间不能用括号隔开。, }0 Y8 A  U0 u0 W6 N
    指针式调用% P4 F1 A- \) Q" c  j
    ClassName* p; // 被调用的对象的指针9 H! m1 {9 P% @0 O3 ~. p8 I
    成员函数指针名字当作正常函数那样写。
    6 H1 [" G- t3 j3 F9 E+ ~4 kp->func(3);: D+ }7 I# o; Q7 q1 W$ ~* e* f
    成员函数指针是指针, func名称前面需加上间接寻址运算符*,变成函数对象。
    - j" O) q! y/ j' Lp->*func(3);. Y6 P( A- s7 r
    最后用括号把调用对象、成员访问运算符->、间接寻址运算符*、和成员函数指针的名称包围起来。' B) ~! r: e; W* ?6 ]; e
    (p->*func)(3);
    * x# G; \2 ~9 B4 Z: D& F, a. U函数指针使用完整例子0 Z' H" l6 W6 r& W3 `
    struct Cal
    9 U" p, ^7 h. W: y{
    " g$ r1 a8 ]$ e3 h) E    int add(int a, int b); 7 Z, j7 r, I2 p2 j# k- k
        int sub(int a, int b);/ b. t4 n- p5 H9 n& L. E7 V
    };
    : G; E) w1 U- u6 R  S2 r3 N' N. Z
    int main(), @% q+ B# m* a6 i
    {
    ) J+ M3 I9 ?+ c+ N" I    int (Cal::*fun)(int, int) = &Cal::add;
    4 ^; G+ U; @) C. ]$ v5 \* D    fun = &Cal::sub;+ {6 p; P3 D8 T0 {9 P/ b# |
    0 c6 e; U# P. I- t& b7 s( `  e+ m8 H
        Cal* p_cal = new Cal();
    : ~/ ]" H, F! U) K0 _9 Q    int r1 = (p_cal->*fun)(2, 3);) L6 y' |( V+ w' h- d+ F4 p. T
        delete p_cal;( I" u$ f$ B2 D6 u+ i. c# Y
    ; C( l" M% V2 \" {
        Cal local_cal;" h" R/ n0 n* b/ [
        int r2 = (local_cal.*fun)(8, 6);
    9 Q( l2 _1 ^6 c& G9 c}: s3 C; g7 S6 g/ a
    " d4 B) l: B! e( k8 d% |
    成员变量指针- Z  v  {) k0 r) I: r
    成员变量指针比成员函数指针还要简单些,没有函数调用, 无需考虑函数调用和间接引用符*的优先级问题。
    1 u, V+ C/ ?# ^6 `/ r2 M" M( ]3 M3 N2 S( N
    成员变量指针的定义' e7 C4 u, {* F4 `3 A" ~" X
    假如以下结构体C。
    5 I! G0 L0 \4 s) @' y; U, v7 B! X7 V
    struct C 2 A- r5 ~$ [* _7 n# {+ p/ }
    {
    % Y- D' E+ N) B4 h, v+ C    int m; 4 N9 r! ], x7 z+ J; G3 i) [9 V
    };9 }, z. M  Y, i% B! s
    单个成员变量指针定义 5 n6 a9 g6 A! N- X. v; P" D( b# H
    假设名称为p, 类似静态成员变量定义那样声明
    + \; R4 B; ^6 b1 G/ nint C::p;  f& f5 ]7 A8 c+ y, N/ u
    在名称前面加上指针标识号* ' H5 a' O: c& c' w, w( x$ ^2 \' @8 s
    int C::*p;
    6 V- N' e  ^6 H0 Vtypedef或using方式定义7 C, [4 u9 E( t2 [2 p/ c  L( m( H7 R
    typedef int C::*MemberPointer;
    * H, p' J' ~4 L! M& iusing MemberPointer = int C::*;! g4 Z' |% ]: O9 x( l3 y
    成员变量指针的使用。
    : S6 W6 s; P7 [" e! T$ l类似成员函数指针那样,直接使用指向成员的指针运算符:.* 和->*即可。8 S3 [/ n# p# \: r: H' X8 l* I- G4 z/ _
    成员变量指针, 能让我们实现一些遍历成员的动态功能。 例如把一个类/结构体的多个同类型的成员变量放进一个容器里,然后遍历访问这些成员变量。# K! A0 C, e8 W( p" @% h/ I1 M
    $ r2 S& T; a  Q$ E
    完整例子  S, w3 d* B! b! z6 L  ~+ u
    struct C { int m; };
    ; q  ~, o9 B, P8 H6 Jint main()# P0 `5 Y) j! w$ O  G6 g
    {/ s/ W3 G+ l) e5 g* i( T
        int C::* p = &C::m;          // pointer to data member m of class C
    % O4 ?" H. O8 L- a) Q& z    C c = {7};
    9 L' G6 |. e  U' k7 G3 I, D4 N    std::cout << c.*p << '\n';   // prints 7! t- S! F! L% _' ]
        C* cp = &c;
    9 K% H+ z+ S: y& |& ^    cp->m = 10;% y; X+ c& t  G7 ^6 E) }
        std::cout << cp->*p << '\n'; // prints 10
    % n4 F4 d" g. B$ z% r- G- H! n5 X9 W, [% J2 O, C
    ————————————————+ S9 M" z4 Z& d& W5 H
    版权声明:本文为CSDN博主「南风fahaxiki」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。. s/ \9 ]# v8 w6 N& b( V
    原文链接:https://blog.csdn.net/m0_64407685/article/details/126788115
    ; Y5 v3 _3 u) s+ G/ n+ M* o
    , [  |7 {% X6 S, Y3 x
    2 u. _7 a: q( A: Y, {+ u( a& r9 Q
    zan
    转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
    您需要登录后才可以回帖 登录 | 注册地址

    qq
    收缩
    • 电话咨询

    • 04714969085
    fastpost

    关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

    手机版|Archiver| |繁體中文 手机客户端  

    蒙公网安备 15010502000194号

    Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

    GMT+8, 2026-7-10 10:40 , Processed in 0.292227 second(s), 51 queries .

    回顶部