我遇到了这个奇怪的代码片段,它编译得很好:
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
return 0;
}
为什么c++有这个指针指向类的非静态数据成员?在实际代码中,这个奇怪的指针有什么用呢?
我遇到了这个奇怪的代码片段,它编译得很好:
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
return 0;
}
为什么c++有这个指针指向类的非静态数据成员?在实际代码中,这个奇怪的指针有什么用呢?
当前回答
我喜欢*和&运算符:
struct X
{
int a {0};
int *ptr {NULL};
int &fa() { return a; }
int *&fptr() { return ptr; }
};
int main(void)
{
X x;
int X::*p1 = &X::a; // pointer-to-member 'int X::a'. Type of p1 = 'int X::*'
x.*p1 = 10;
int *X::*p2 = &X::ptr; // pointer-to-member-pointer 'int *X::ptr'. Type of p2 = 'int *X::*'
x.*p2 = nullptr;
X *xx;
xx->*p2 = nullptr;
int& (X::*p3)() = X::fa; // pointer-to-member-function 'X::fa'. Type of p3 = 'int &(X::*)()'
(x.*p3)() = 20;
(xx->*p3)() = 30;
int *&(X::*p4)() = X::fptr; // pointer-to-member-function 'X::fptr'. Type of p4 = 'int *&(X::*)()'
(x.*p4)() = nullptr;
(xx->*p4)() = nullptr;
}
事实上,只要成员是公共的或静态的,所有都是真的
其他回答
假设你有一个结构。在那个结构里面 *某种名字 *两个相同类型但含义不同的变量
struct foo {
std::string a;
std::string b;
};
好的,现在假设你在一个容器里有一堆foo:
// key: some sort of name, value: a foo instance
std::map<std::string, foo> container;
好吧,现在假设您从不同的源加载数据,但是数据以相同的方式呈现(例如,您需要相同的解析方法)。
你可以这样做:
void readDataFromText(std::istream & input, std::map<std::string, foo> & container, std::string foo::*storage) {
std::string line, name, value;
// while lines are successfully retrieved
while (std::getline(input, line)) {
std::stringstream linestr(line);
if ( line.empty() ) {
continue;
}
// retrieve name and value
linestr >> name >> value;
// store value into correct storage, whichever one is correct
container[name].*storage = value;
}
}
std::map<std::string, foo> readValues() {
std::map<std::string, foo> foos;
std::ifstream a("input-a");
readDataFromText(a, foos, &foo::a);
std::ifstream b("input-b");
readDataFromText(b, foos, &foo::b);
return foos;
}
此时,调用readValues()将返回一个“input-a”和“input-b”一致的容器;所有的键都将出现,带有a或b或两者都有的foo。
下面是一个例子,其中指向数据成员的指针可能很有用:
#include <iostream>
#include <list>
#include <string>
template <typename Container, typename T, typename DataPtr>
typename Container::value_type searchByDataMember (const Container& container, const T& t, DataPtr ptr) {
for (const typename Container::value_type& x : container) {
if (x->*ptr == t)
return x;
}
return typename Container::value_type{};
}
struct Object {
int ID, value;
std::string name;
Object (int i, int v, const std::string& n) : ID(i), value(v), name(n) {}
};
std::list<Object*> objects { new Object(5,6,"Sam"), new Object(11,7,"Mark"), new Object(9,12,"Rob"),
new Object(2,11,"Tom"), new Object(15,16,"John") };
int main() {
const Object* object = searchByDataMember (objects, 11, &Object::value);
std::cout << object->name << '\n'; // Tom
}
这是我能想到的最简单的例子,它传达了这个特性很少相关的情况:
#include <iostream>
class bowl {
public:
int apples;
int oranges;
};
int count_fruit(bowl * begin, bowl * end, int bowl::*fruit)
{
int count = 0;
for (bowl * iterator = begin; iterator != end; ++ iterator)
count += iterator->*fruit;
return count;
}
int main()
{
bowl bowls[2] = {
{ 1, 2 },
{ 3, 5 }
};
std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::apples) << " apples\n";
std::cout << "I have " << count_fruit(bowls, bowls + 2, & bowl::oranges) << " oranges\n";
return 0;
}
这里需要注意的是传递给count_fruit的指针。这样就不必单独编写count_apples和count_oranges函数。
IBM有更多关于如何使用它的文档。简单地说,您使用指针作为类的偏移量。你不能在它们所指向的类之外使用这些指针,所以:
int Car::*pSpeed = &Car::speed;
Car mycar;
mycar.*pSpeed = 65;
It seems a little obscure, but one possible application is if you're trying to write code for deserializing generic data into many different object types, and your code needs to handle object types that it knows absolutely nothing about (for example, your code is in a library, and the objects into which you deserialize were created by a user of your library). The member pointers give you a generic, semi-legible way of referring to the individual data member offsets, without having to resort to typeless void * tricks the way you might for C structs.
我喜欢*和&运算符:
struct X
{
int a {0};
int *ptr {NULL};
int &fa() { return a; }
int *&fptr() { return ptr; }
};
int main(void)
{
X x;
int X::*p1 = &X::a; // pointer-to-member 'int X::a'. Type of p1 = 'int X::*'
x.*p1 = 10;
int *X::*p2 = &X::ptr; // pointer-to-member-pointer 'int *X::ptr'. Type of p2 = 'int *X::*'
x.*p2 = nullptr;
X *xx;
xx->*p2 = nullptr;
int& (X::*p3)() = X::fa; // pointer-to-member-function 'X::fa'. Type of p3 = 'int &(X::*)()'
(x.*p3)() = 20;
(xx->*p3)() = 30;
int *&(X::*p4)() = X::fptr; // pointer-to-member-function 'X::fptr'. Type of p4 = 'int *&(X::*)()'
(x.*p4)() = nullptr;
(xx->*p4)() = nullptr;
}
事实上,只要成员是公共的或静态的,所有都是真的