【问题标题】:Esoteric C++ operators深奥的 C++ 运算符
【发布时间】:2010-05-10 22:01:54
【问题描述】:

以下深奥的 C++ 运算符的用途是什么?

指向成员的指针

::*

通过指针将指针绑定到成员

->*

通过引用绑定指向成员的指针

.*

(reference)

【问题讨论】:

  • 无论维基百科怎么说,::* 不是操作员。

标签: c++ operators


【解决方案1】:

指向成员的指针允许您拥有一个相对于特定类的指针。

所以,假设您有一个包含多个电话号码的联系人类。

class contact
{
    phonenumber office;
    phonenumber home;
    phonenumber cell;
};

这个想法是,如果你有一个算法需要使用电话号码,但应该在算法之外决定哪个电话号码,指向成员的指针解决了问题:

void robocall(phonenumber contact::*number, ...);

现在robocall的呼叫者可以决定使用哪种类型的电话号码:

robocall(&contact::home, ...);    // call home numbers
robocall(&contact::office, ...);  // call office number

.* 和 ->* 一旦有了指针就会发挥作用。所以在robocall里面,你会这样做:

contact c = ...;
c.*number;    // gets the appropriate phone number of the object

或:

contact *pc = ...;
pc->*number;

【讨论】:

  • 在Pointers to members 上的 InformIT 上有一个可读指南。
  • 这里有一个很好的例子:msdn.microsoft.com/en-us/library/k8336763.aspx
  • 是的,指向成员的指针非常方便——我广泛使用它们来序列化字节流和数据库结果集。有点像穷人的倒影。使用成员指针(字段和方法),您可以轻松设置允许动态操作类型的数据结构,而只需很少的静态知识(通常有助于拥有一个通用的基础和一些可用的访问者式调度方法)。
【解决方案2】:

没有像::* 这样的运算符,而且从来没有。我不知道你从哪里弄来的。

至于->* 和.* - 这些是pointer-to-member 类型指针的取消引用运算符。

struct S {
  int i;
};

int main() {
  int S::*pi = &S::i; // pointer of pointer-to-member type

  S s;
  S* ps = &s;

  s.*pi = 0; // operator `.*` used
  assert(s.i == 0);

  ps->*pi = 1; // operator `->*` used
  assert(s.i == 1);
}

至于指向成员的指针是什么……你最喜欢的 C++ 书籍在这个主题上是怎么说的?

【讨论】:

  • 我从维基百科获得了 ::* 作为我的问题的参考。
  • ::* 在 g++ 中编译得很好。
  • @Neil G:究竟是什么“在 g++ 中编译得很好”?
  • @Neil G::: 是一个运算符,因为标准是这样说的,并且因为 :: 标记在 C++ 语法中扮演运算符的角色。 ::* 不是运算符,因为标准在列出运算符时没有提及它,并且因为在解析 C++ 时没有 ::* 标记。 int x = 5+-2; 编译,并不意味着+- 是一个操作符。
  • @Neil G:首先,Samuel 的回答中没有 ::* 运算符。您可以找到::* 的唯一地方是他的答案(以及我的答案)是声明。声明中没有“运算符”之类的东西,即使某些东西可能看起来像运算符。当您在代码中看到int i = 1; 时,= 位不是运算符,它只是声明的句法元素。
【解决方案3】:

它们与指向成员的指针和指向成员函数的指针有关。

struct Foo {
    int a() { return 1; }
    int b() { return 2; }
    int c;
};

int main() {
    Foo f;
    f.c = 3;

    typedef int (Foo::*member_fn)(); // pointer-to-member-function
    typedef int (Foo::*data_member); // pointer-to-member

    member_fn mf = &Foo::a;
    (f.*mf)(); // calls the member function pointed to by mf. returns 1
    mf = &Foo::b;
    (f.*mf)(); // This time, returns 2, since mf points to b
    Foo *fp = &f;
    (fp->*mf)(); // same thing, via pointer to f instead of object/reference f.

    data_member dm = &Foo::c;
    f.*dm; // is 3
    f.*dm = 5;
    f.c;  // is now 5.

    Foo f2; // another instance
    f2.c = 12;
    f2.*dm;  // is 12. Same pointer-to-member, different object.
}

虽然看起来像一个,::* 不是运算符。它是:: 运算符和* operator 类型修饰符并排在一起。为了证明这一点而不求助于阅读标准,请尝试添加空格::: * 编译,. * 没有,-> * 也没有。

至于它们的实际用途——与函数指针的原理相同。你不会像我上面那样使用它们,在这种情况下你可以只按名称调用函数,但你可以将它们作为参数传递或从函数中返回、存储它们,或者根据复杂的逻辑选择几个之一。

如果有帮助,我相信选择了这样的语法,尽管.* 是一个不可分割的单个运算符,但您可以想象*dm“意味着”c,即 dm 指向的成员。所以如果dm指向c,那么f.*dm和f.c是一样的。

【讨论】:

    【解决方案4】:

    查看C++ FAQ Lite's section on pointers to member functions。搜索您正在谈论的特定“运算符”(在大多数浏览器中,Ctrl-F 打开一个查找/搜索对话框,允许您在网页中搜索文本),它应该可以帮助您更好地理解事物。

    【讨论】:

      【解决方案5】:

      一个过于简单的答案 - 这些运算符允许将成员函数称为“常规”函数(至少从最终用户的角度来看是一样的)。现实世界的例子——它们在各种回调实现中被大量使用。

      【讨论】:

        【解决方案6】:

        这些允许您拥有指向绑定到类的特定实例的成员函数(和成员变量)的指针。

        指向成员函数的指针对于状态模式的轻量级实现非常有用。一般来说,任何时候你想随着时间的推移改变一个对象的行为而不求助于切换整个对象,你可以考虑使用指向成员函数的指针。

        如果您想要,可以使用指向成员变量的指针,例如,实现一个通用算法来搜索结构数组以查找具有给定字段的特定值的条目。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-10-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-01
          • 1970-01-01
          • 2012-11-26
          相关资源
          最近更新 更多