.*、->* 和 .-> 在C++中是什么意思?

What does .*, ->* and .-> mean in C++?

本文关键字:gt 是什么 意思 C++      更新时间:2023-10-16

我最近一直在学习如何使用std::mem_fn图书馆工具。在入门第5版C++中,他们给出了一个std::mem_fn用法的例子,在下面的代码片段中svecstring vector

auto f = mem_fn(&string::empty); // f takes a string or a string*
f(*svec.begin()); // ok: passes a string object; f uses .* to call empty
f(&svec[0]); // ok: passes a pointer to string; f uses .-> to call empty

注意:在上面的代码片段中没有使用 ->*

虽然我了解.*->*的用法.我不清楚。

所以,我的问题是.*->*.->做什么?

你有一个对象o和一个指向其成员m的指针。运算符.*允许您访问对象的尖头成员:

o.*m

您有一个指向对象p的指针和一个指向其成员m的指针。运算符->*允许您访问指向对象的指向构件:

p->*m

恐怕运算符.->不存在。

运算符.*->*调用成员函数(顺便说一句,.->在C++中没有意义 - 这是一个语法错误(。

这些是二元运算符。左操作数是对象(对于.*(或指向对象的指针(对于->*(,右操作数是指向成员(可以是成员字段或成员函数(的指针。应用此运算符的结果是能够使用成员字段或方法。

也许从历史的角度来看,这些运算符是有意义的。假设您使用指向函数的常规 C 指针:

typedef int (*CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &CalcResult42;
...
int result = my_calc_func(11, 22, 33);

如果您决定以面向对象的方式"重写"程序怎么办?您的计算函数将是类中的方法。要创建指向它的指针,您需要一个新类型,即指向成员函数的指针:

typedef int (MyClass::*CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &MyClass::CalcResult42;
...
MyClass my_object;
int result = (my_object.*my_calc_func)(11, 22, 33);

当我尝试记住这个.*运算符的语法时,我总是使用这个类比 - 这很有帮助,因为常规指针到函数语法不那么复杂并且使用更频繁。

请注意括号:

int result = (my_object.*my_calc_func)(11, 22, 33);

使用此.*运算符时几乎总是需要它们,因为它的优先级较低。即使my_object .* (my_calc_func(11, 22, 33))毫无意义,如果没有括号,编译器也会尝试理解它。

->*运算符的工作方式基本相同。如果要应用该方法的对象由指针给出,则将使用它:

typedef int (*MyClass::CalcResult)(int x, int y, int z);
CalcResult my_calc_func = &MyClass::CalcResult42;
...
MyClass my_object1, my_object2;
MyClass* my_object = flag ? &my_object1 : &my_object2;
int result = (my_object->*my_calc_func)(11, 22, 33);

.*->* 运算符称为指向成员访问运算符的指针,就像它们的名字一样,它们允许您访问对象的数据或函数成员,给定指向该类成员的适当指针。

struct foo
{
    int a;
    float b;
    void bar() { std::cout << "barn"; }
};
int main()
{
    int foo::* ptra = &foo::a;
    float foo::* ptrb = &foo::b;
    void (foo::* ptrbar)() = &foo::bar;
    foo f;
    foo * fptr = &f;
    f.*ptra = 5;
    f.*ptrb = 10.0f;
    (f.*ptrbar)();
    fptr->*ptra = 6;
    fptr->*ptrb = 11.0f;
    (fptr->*ptrbar)();
    return 0;
}