我遇到了这个奇怪的代码片段,它编译得很好:
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++有这个指针指向类的非静态数据成员?在实际代码中,这个奇怪的指针有什么用呢?
当前回答
我使用它的一种方式是,如果我有两个如何在一个类中做某事的实现,我想在运行时选择一个,而不必连续地通过if语句,即。
class Algorithm
{
public:
Algorithm() : m_impFn( &Algorithm::implementationA ) {}
void frequentlyCalled()
{
// Avoid if ( using A ) else if ( using B ) type of thing
(this->*m_impFn)();
}
private:
void implementationA() { /*...*/ }
void implementationB() { /*...*/ }
typedef void ( Algorithm::*IMP_FN ) ();
IMP_FN m_impFn;
};
显然,这只有在你觉得代码被敲打到足够的if语句减慢事情完成时才有用。在某个密集算法的深处。我仍然认为它比if语句更优雅,即使在它没有实际用途的情况下,但这只是我的观点。
其他回答
假设你有一个结构。在那个结构里面 *某种名字 *两个相同类型但含义不同的变量
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>
using namespace std;
class Car
{
public:
int speed;
};
int main()
{
int Car::*pSpeed = &Car::speed;
Car c1;
c1.speed = 1; // direct access
cout << "speed is " << c1.speed << endl;
c1.*pSpeed = 2; // access via pointer to member
cout << "speed is " << c1.speed << endl;
return 0;
}
至于你为什么要这样做,它给了你另一种间接的层次,可以解决一些棘手的问题。但说实话,我从未在自己的代码中使用过它们。
编辑:我想不出一个令人信服的使用指针成员数据。指向成员函数的指针可以在可插拔的体系结构中使用,但是在这么小的空间里生成一个例子再次让我感到挫败。以下是我最好的(未经测试)尝试-一个Apply函数,在应用用户选择的成员函数到对象之前,会做一些前后处理:
void Apply( SomeClass * c, void (SomeClass::*func)() ) {
// do hefty pre-call processing
(c->*func)(); // call user specified function
// do hefty post-call processing
}
c->*func周围的括号是必要的,因为->*操作符的优先级低于函数调用操作符。
指向类的指针不是真正的指针;类是一个逻辑构造,在内存中没有物理存在,然而,当你构造一个指向类成员的指针时,它会给出一个指向该成员所在类的对象的偏移量;这给出了一个重要的结论:由于静态成员不与任何对象相关联,因此指向成员的指针不能指向静态成员(数据或函数) 考虑以下几点:
class x {
public:
int val;
x(int i) { val = i;}
int get_val() { return val; }
int d_val(int i) {return i+i; }
};
int main() {
int (x::* data) = &x::val; //pointer to data member
int (x::* func)(int) = &x::d_val; //pointer to function member
x ob1(1), ob2(2);
cout <<ob1.*data;
cout <<ob2.*data;
cout <<(ob1.*func)(ob1.*data);
cout <<(ob2.*func)(ob2.*data);
return 0;
}
来源:完整参考c++ - Herbert Schildt第四版
我认为,只有当成员数据相当大(例如,另一个相当庞大的类的对象),并且您有一些外部例程,只对该类的对象引用起作用时,才会想要这样做。你不想复制成员对象,所以这让你可以传递它。
指向成员的指针是c++的类型安全等价于C的offsetof(),它在stddef.h中定义:两者都返回某个字段位于类或结构中的信息。虽然在c++中也可以将offset()用于某些足够简单的类,但在一般情况下,它会失败,尤其是虚拟基类。因此指针成员被添加到标准中。它们还提供了更简单的语法来引用实际字段:
struct C { int a; int b; } c;
int C::* intptr = &C::a; // or &C::b, depending on the field wanted
c.*intptr += 1;
要比:
struct C { int a; int b; } c;
int intoffset = offsetof(struct C, a);
* (int *) (((char *) (void *) &c) + intoffset) += 1;
至于为什么要使用offsetof()(或指向成员的指针),在stackoverflow的其他地方有很好的答案。这里有一个例子:宏的C偏移是如何工作的?