【问题标题】:What does operator.*() do?operator.*() 是做什么的?
【发布时间】:2015-04-27 11:53:27
【问题描述】:

operator.*() 是做什么的?它的目的是什么?

它被记录为Pointer-to-member,与->* 完全相同。这两个是一样的吗?

Scott Meyers 在更有效的 C++ 中,第 7 项解释说 .* 不可重载,而 ->* 是。这是为什么呢?

【问题讨论】:

  • .*->* 什么 .->
  • 该页面只是说它与->* 具有相同的优先级,而不是“完全相同”。它很相似,但适用于像 . 这样的对象/引用,而不是像 -> 这样的指针。
  • @PanagiotisKanavos 这似乎是不合理的。我从未声称运营商不存在。
  • @5gon12eder C++ 确实有.*->* 运算符,其中* 是运算符语法的一部分。
  • @5gon12eder 不,不。它根本不是占位符,.*->* 真正的运算符。

标签: c++ operators


【解决方案1】:

它是一个成员的指针。示例:

// This functions waits until predicate evalues false
void waitSomething(bool (one_class::*predicate)(),one_class& that)
{
    while ((that.*predicate)())
    {
        sleep(100);
    }
}

你可以这样称呼:

one_class a;
waitSomething(&a::*predicate,a); //predicate is an internal function member

你也可以使用属性。

->* 用于指针:

// This functions waits until predicate evalues false
void waitSomething(bool (one_class::*predicate)(),one_class* that)
{
    while ((that->*predicate)())
    {
        sleep(100);
    }
}

【讨论】:

  • 顺便说一句,OP 还问为什么 .* 不可重载。
【解决方案2】:

它被设计用于:

类类型的左操作数

指向“此类类型的成员”的指针的右操作数

#include <iostream>
#include <string>
using std::string;

class Foo{
public:
  int f(string str){
    std::cout<<"Foo::f()"<<std::endl;
    return 1;
  }
};

int main(int argc, char* argv[]){
  int (Foo::*fptr) (string) = &Foo::f;
  Foo obj;
  (obj.*fptr)("str");//call: Foo::f() through an object
  Foo* p=&obj;
  (p->*fptr)("str");//call: Foo::f() through a pointer
}

请注意,我没有生成此代码,它来自一个解释了它是如何工作的教程,但实际上并不是目的是什么

关于可重载性的区别与 between 相同。和->,所以它不是特别针对这种情况,并且有关于这个的主题,比如this one

委员会正在决定这些事情,并不是每次都有明显的理由,但这与 x-> 可以被视为 (*x) 的事实相一致, .() 不能超载,但 *() 可以,因此这些组合意味着 -> 可以超载,因为“其中一部分具有不同的写法”可以超载

我最后说的只是我想继续欣赏 c++ 的美丽和连贯性

【讨论】:

    【解决方案3】:

    正如已经回答的那样,不,.*-&gt;* 不是同一个意思。假设没有使用重载运算符,a-&gt;*b 表示(*a).*b,即.* 与类类型一起使用,-&gt;* 与指向类类型的指针一起使用。就像使用内置运算符时a-&gt;b 表示(*a).b 一样。

    ..* 都不能重载,因为在编写标准时不清楚这是否会产生负面影响。 . 是这些中更有用的,is still being considered for a future version of C++,但第一个建议使 dates back to 1990 可重载(远在第一个 C++ 标准发布之前)。需要解决的一些问题涉及选择当a.b 对内置运算符有效但 有效(伪代码)(a.operator.()).b 时要做什么。然后内置运算符是否会被使用,或者这应该是一个错误?两者似乎都不是特别理想。

    重载. 运算符的一些建议还包括重载.* 运算符,其他则没有。让.* 本身可重载的需求并不多,所以如果它确实在某个时候被接受,它可能会与. 一起发生,这需要很长时间。

    【讨论】:

    • 如果可能的话,我希望它很像超载&amp;:被解雇的单程票:p
    • @Quentin There are a few good uses of overloaded operator&amp;,当需要内置运算符时,可以不依赖&amp;获取地址,就像可以直接调用成员函数一样即使operator. 被重载,也会在对象上。 (你可以写addressof(obj)-&gt;fun() 而不是obj.fun()。)
    【解决方案4】:

    我不确定这是否对你特别有帮助,但这是我从你的问题中学到的。

    重载运算符-&gt;* (which is a real thing…) 和运算符-&gt; 的合理用例可能是为间接成员访问提供对托管对象的透明访问(考虑std::unique_ptr)。但是请注意,std::unique_ptr 会重载运算符 -&gt;,但不会重载运算符 -&gt;*

    就像我们不能重载运算符.一样,我们也不能重载运算符.*,因为it was decided to be like this

    所以这里有一个有点傻的类,它包装了一个对象并假装是一个指向它的指针。如果托管对象由具有托管生命周期的指针持有,该示例将更有意义,但我想避免与成员访问无关的资源管理代码使示例混乱。

    // C++14
    
    #include <iostream>
    #include <utility>
    #include <vector>
    
    template<typename T>
    class PointerLike
    {
    
    private:
    
      T object_;
    
    public:
    
      template<typename... ParamT>
      PointerLike(ParamT&&... params) : object_ {std::forward<ParamT>(params)...}
      {
      }
    
      // The 'const' overloads have been omitted for the sake of brevity.
    
      // "Dereferences" the handle and obtains a reference to the managed object.
      T&
      operator*()
      {
        return this->object_;
      }
    
      // Accesses a member of the managed object.
      T *
      operator->()
      {
        return &(this->object_);
      }
    
      // Indirectly invokes a function member of the managed object.
      template<typename RetT, typename... ArgT>
      decltype(auto)
      operator->*(RetT(T::*mfunc)(ArgT...))
      {
        return [=](ArgT... args)->RetT{
          return (object_.*mfunc)(std::forward<ArgT>(args)...);
        };
      }
    };
    
    int
    main()
    {
      typedef std::vector<int> ivec;
      typedef void (ivec::*append_member_type)(int&&);
      append_member_type append = &ivec::push_back;
      PointerLike<ivec> pl {1, 2, 3, 4};
      pl->push_back(5);    // pointer-like direct member access
      (pl->*append)(6);    // pointer-like indirect member access ("natural" way)
      ((*pl).*append)(7);  // pointer-like indirect member access
      for (const auto& v : *pl)
        std::cout << v << std::endl;
    }
    

    程序将输出 1 到 7 的整数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多