多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
## 一.指向数据成员的指针 ### (一) 使用普通指针指向数据成员 1. 直接使用一个普通的指针变量接受一个数据成员的地址。 ```c++ //类的声明 class Complex { public: double real_; double imaginary_; Complex(double real,double imaginary):real_(real),imaginary_(imaginary){} }; //定义 Complex c(1,2); double *cp = &c.real_; ``` ### \[$\](二) 使用数据成员指针指向非静态数据成员 1. **语法** `类型 类名::*指针变量名` ```c++ class Complex { public: double real_; double imaginary_; Complex(double real, double imaginary) : real_(real), imaginary_(imaginary) {} }; //定义对象 Complex c(1, 2); //定义指针并初始化 double Complex::*dmp = &Complex::real_; //取值 cout << c.*dmp; ``` 2. **数据成员指针的值** 为数据成员所在地址相对于对象起始地址的偏移值(这个偏移值是按照数据成员声明的顺序计算的,因此对象定义前就可以取值),空指针为`-1` 。 ```c++ class Complex { public: double real_; double imaginary_; Complex(double real, double imaginary) : real_(real), imaginary_(imaginary) {} int calculate(int a) { return 0; }; }; //对象定义 Complex c(8, 2), d(3, 4); double Complex::*dmp = NULL; printf("%d\n",dmp);//-1 dmp = &Complex::real_; printf("%d\n",dmp);//0 dmp = &Complex::imaginary_; printf("%d\n",dmp);//8 ``` >[warning] 使用 `cout` 输出时,成员指针会转换成 `bool` ,导致输出结果不唯一。 ## 二.指向非静态成员函数的指针 若有以下类: ```c++ class Box { private: int width_; int height_; public: Box(int width, int height) : width_(width), height_(height) { } int calculate() { return this->width_ * this->height_; } Box &set_width(int width) { this->width_ = width; return *this; } Box &set_height(int height) { this->height_ = height; return *this; } }; ``` 1. 定义和初始化一个成员函数指针 + **语法** `函数返回值 (类名::*指针变量名)(参数表)` ```c++ //用函数名初始化 Box & (Box::*pb)(int) = &Box::set_height; //不带 & 的写法不是标准写法,部分编译器有可能报错(如VS2019会报C3867) Box & (Box::*pb)(int) = Box::set_height; ``` 2. 通过成员函数指针调用函数 + **语法** `(类名.*指针变量名)(参数表)` ```c++ //定义对象 Box b(10, 20); //调用函数 (b.*pb)(30); //下面代码的意思是调用一个名为ps的函数,然后使用该函数的返回值作为指针指向成员运算符(.*)的运算对象。然而ps并不是一个函数,因此代码将发生错误。 b.*pb(30); ``` 3. [$] **微软编译器下,成员函数指针的值** + 成员函数指针是一个结构体指针,里面包含了偏移量,虚函数表索引,函数地址等数据。 + 对于非虚函数,函数地址就是函数真实的地址。其中函数的第一个参数为 `this` 指针。 + 对于虚函数,函数地址指向一小段代码(一般被称为 `vcall thunk`),用于从虚函数表中寻找虚函数的地址。