“指向类成员变量的指针”,这个术语中包含了"类成员变量"的术语,但是严格的说,这里的成员变量只是指非静态成员变量,这个术语中还包含了"指针"这个术语,但是严格的说,它即不包含地址,行为也不象指针,说得干脆点,那就是"指向类成员变量的指针"并非指针.尽管这个术语有很大的迷惑性,但是就其含义来说,可以把一组同类型的变量抽象为一个"指向变量的指针",同样的道理,可以把一组类中同类型的类成员变量抽象为一个"指向类成员变量的指针",两者是一致的。
但是一个"指向类成员变量的指针"并不包含一个地址,简单点说,实际上它是一个成员变量在类中的偏移量.当然,严格点说,因为C++标准并为对"指向类成员变量的指针"如何实现做任何规定,说"指向类成员变量的指针"是一个整数的偏移量就不是一定正确,但是,大多数编译器确实是这样做的.下面我们看看"指向类成员变量的指针"是如何使用的?
举个例子:
// addressof example
class PTM {
public:
int iValue;
int jValue;
static float fValue;
};
float PTM::fValue;
void PrintAll(PTM* point) {
std::cout << "PTM Print All" << std::endl;
std::cout << point->PTM::iValue << std::endl;
std::cout << point->PTM::jValue << std::endl;
}
void Print(PTM* point, int PTM::* p) {
std::cout << point->*p << std::endl;
}
int main() {
int PTM::*pValue = &PTM::iValue; // OK: non-static
//float PTM::*pfValue = &PTM::fValue; // C2440 error: static
float *spfValue = &PTM::fValue; // OK
std::cout << "int PTM::*pValue = &PTM::iValue;" << std::endl;
std::cout << "float *spfValue = &PTM::fValue;" << std::endl << std::endl;
std::cout << "typeid(pValue).name(): " << typeid(pValue).name() << std::endl;
std::cout << "typeid(spfValue).name(): " << typeid(spfValue).name() << std::endl << std::endl;
PTM ptm;
ptm.iValue = 98;
ptm.jValue = 99;
int* iValue = &ptm.iValue;
std::cout << "int* iValue = &ptm.iValue;" << std::endl;
std::cout << "typeid(iValue).name(): " << typeid(iValue).name() << std::endl << std::endl;
printf("address of pValue: %p\n", pValue);
Print(&ptm, pValue);
pValue = &PTM::jValue;
std::cout << "pValue = &PTM::jValue;" << std::endl;
printf("address of pValue: %p\n", pValue);
Print(&ptm, pValue);
PrintAll(&ptm);
return 0;
}
输出结果为:
:g++ -std=c++17 -O0 main.cc -o main
main.cc:47:37: warning: format specifies type 'void *' but the argument has type 'int PTM::*' [-Wformat]
printf("address of pValue: %p\n", pValue);
~~ ^~~~~~
main.cc:51:37: warning: format specifies type 'void *' but the argument has type 'int PTM::*' [-Wformat]
printf("address of pValue: %p\n", pValue);
~~ ^~~~~~
2 warnings generated.
:./main | c++filt
int PTM::*pValue = &PTM::iValue;
float *spfValue = &PTM::fValue;
typeid(pValue).name(): int PTM::*
typeid(spfValue).name(): float*
int* iValue = &ptm.iValue;
typeid(iValue).name(): int*
address of pValue: 0x0
98
pValue = &PTM::jValue;
address of pValue: 0x4
99
PTM Print All
98
99