【问题标题】:Is it possible to pass "this" by default?是否可以默认传递“this”?
【发布时间】:2016-09-11 14:41:11
【问题描述】:

是否可以默认传递this

这是我目前拥有的

class A
{
public:
    template<typename T>
    void dowithT(T t) {}
};

class B
{
public:
    A a;

    B()
    {
        //Calling 'dowithT' with 'this'
        a.dowithT(this);
    }
};

这个函数每次都需要从函数调用者那里传递this。所以想知道有没有办法封装这个任务,这样就不用把this传给dowithT了。

我试图做这样的事情:

class A
{
public:
    // '= this' doesn't compile
    template<typename T>
    void dowithT(T t = this) {}
};

class B
{
public:
    A a;

    B()
    {
        //Calling 'dowithT' without 'this'
        a.dowithT();
    }
};

不幸的是,我不能使用模板,所以我的第一个解决方案不是一个选项。

这可能吗?

编辑:我在下面用我自己的实现给出了一个具体的答案。最后还有一些我想要的细节。

【问题讨论】:

  • 您不需要将this 指针作为参数传递。它总是出现在这个类的上下文中。尝试直接使用它。
  • @MukulGupta:有问题的this 用于class B,默认情况下class A 不可用。
  • 顺便说一句,我认为你应该重新考虑你的班级设计。 “我写了一个类,它需要从函数的调用者那里传递“this”。” - 这听起来真是个坏主意......
  • @Cornstalks:我的错。
  • @Christian Hackl:我使用“this”作为参数,因为我已经封装了创建任务:function&lt;void()&gt; (std::bind(func, res),其中“res”是“this”指针的含义

标签: c++ parameter-passing this


【解决方案1】:

在尝试了你提到的各种事情之后,我想自己给出我对问题的答案/解决方案,以澄清一些细节:

#include <iostream>
using namespace std;

#include <functional>

template <typename CallerType>
class AFunctionConstructor{
private:
    virtual void abstr()
    {}
public:
    
    typedef void(CallerType::*CallerTypeFunc)();

    function<void()>* constructFunction(CallerTypeFunc func)
    {
        CallerType* newMe = dynamic_cast<CallerType*> (this);
        return new function<void()>(std::bind(func,newMe));
    }       
};

class A : public function<void()>
{
protected:
    
     
public:
    A();
    A(function<void()>* func) : function<void()>(*func)
    {}

};


//  now create ressource classes
//  they provide functions to be called via an object of class A

class B : public AFunctionConstructor<B>
{
    void foo()
    {
        cout << "Foo";
    }

public:
    A a;

    B() : a(constructFunction(&B::foo)) {}
};

class C : public AFunctionConstructor < C >
{
    void bar()
    {
        cout << "Bar";
    }

public:
    A a;

    C() : a(constructFunction(&C::bar)) {}
};

int main()
{
    B b;
    C c;

    b.a(); 
    c.a();

    cout << endl;

    A* array[5];

    array[0] = &b.a;        //different functions with their ressources
    array[1] = &c.a;        
    array[2] = &b.a;
    array[3] = &c.a;
    array[4] = &c.a;

    for (int i = 0; i < 5; i++)     //this usability i wanted to provide
    {
        (*(array[i]))();
    }

    getchar();
    return 0;
}

输出:

FooBar

FooBarFooBarBar

这是我可以将其按下的有关示例。但我想这是不安全的代码。我偶然发现了其他可能的更简单的方法来实现这一点(std::function 和 lambdas 的其他用途(我可能试图在这里部分重新发明)。

起初我试图将“this”传递给function&lt;void()&gt;*AFunctionConstructor::constructFunction(CallerTypeFunc func)中的绑定函数 ,不过,我现在通过动态上调。 此外,AFunctionConstructor 的功能首先应该在 A 的构造函数中实现。

【讨论】:

    【解决方案2】:

    如果您希望能够传递其他值,您可以使用 B 类中的私有方法作为中继,并使用常量 nullptr 作为特殊值:

    class B
    {
    public:
        A a;
    
        B()
        {
            //Calling 'dowithT' with 'this'
            innerdo();
        }
    private:
        void innerdo(B *p = nullptr) {
            if (p == nullptr) p = this;
            a.dowithT(p);
        }
    };
    

    如果只需要传递this就更简单了

        void innerdo() {
            a.dowithT(this);
        }
    

    【讨论】:

      【解决方案3】:

      您可以通过使用私有 mixin 类提供不带参数的 dowithT 方法来实现您想要的:

      #include <iostream>
      #include <typeinfo>
      
      class A
      {
      public:
          template<typename T>
          void dowithT(T* t) {
            std::cout << "Hello, World" << typeid(*t).name() << std::endl;
          }
      };
      
      template<class Owner>
        struct calls_a
        {
          void dowithT()
          {
            auto p = static_cast<Owner*>(this);
            p->a.dowithT(p);
          }
        };
      
      class B
        : private calls_a<B>
      {
          friend calls_a<B>;
          A a;
      
      public:
          B()
          {
              //Calling 'dowithT' with 'this'
              dowithT();
          }
      };
      
      int main()
      {
        B b;
      
      }
      

      【讨论】:

      • 我可以将您的代码调整到我的代码中,并且在我处理了有关预先存在的模板的所有错误之后,我......好吧,我终于让代码运行了(我很快就会给出自己的答案)。
      • 嗯。您是否准确复制了代码?我从一个完整的工作程序中复制/粘贴了它。
      • 不,我没有复制你的代码,但我使用了你使用的代码
      【解决方案4】:

      代替B 具有A 类型的成员,它可以从A继承,并使用类似"curiously recurring template pattern." 的东西

      如果你不能将 A 类作为模板,你仍然可以这样做:

      class A
      {
          protected:
          template <class T>
          void dowithT()
          {
               T* callerthis = static_cast<T*>(this);
               // callerthis is the "this" pointer for the inheriting object
               cout << "Foo";
          }
      };
      
      class B : public A
      {
          public:
          B()
          {
              dowithT<B>();
              // Or A::dowithT<B>();
          }
      };
      

      dowithT() 只能由继承类调用(因此我将其设为protected),模板参数是调用者自己的类型,否则你会破坏一切。

      【讨论】:

      • 好的,它可能会工作,但我还需要传递一个函数指针类型,我需要弄清楚如何计算模板中的成员函数 ptr 类型
      • @Meph:有什么用?如果每个调用者都有一个方法,比如“foo()”,dowithT() 应该调用,那么你可以使用callerthis-&gt;foo()
      【解决方案5】:

      这里有一种可能性,它可能适合也可能不适合您的需求:

      template<typename T>
      class A
      {
      public:
          A(T t) : t(t) {}
      
          void dowithT()
          {
               cout << "Foo";
          }
      
      private:
          T t;
      };
      
      class B
      {
          public:
          A<B*> a;
      
          B() : a(this)
          {
              a.dowithT();
          }
      };
      

      【讨论】:

      • 这行得通,是的,但如前所述,我不能使用 A 类模板
      • class A 类似于我的代码中的一个类,它是可调用的并且可以加载函数,这样我就可以选择其中一个,它可以带来自己的资源。在这里保持简短:A 必须始终是相同的类型,以便我可以在 A 的数组中使用它的全部功能。如果存在模板,则无法将它们全部写入数组
      【解决方案6】:

      this Athis B 不同。在您的第一个代码中,this 指的是调用者,而在第二个代码中this 指的是callee。因此,您想要做的实际上是不可能的。

      【讨论】:

        【解决方案7】:

        不,这是不可能的。 this 在用作采用 T*(模板或非模板)的函数的参数时并没有什么特别之处,它只是一个指针。

        【讨论】:

          【解决方案8】:

          TL;DR 不,这是不可能的。

          this 在每个类中都不是同一个类型,你不能概括它,所以不,不可能。

          另外,如果doWithT() 是从非成员函数调用的,this 会是什么? nullptr?

          这就是为什么它是不可能的。你必须使用template

          【讨论】:

          • 我的想法类似,但我不确定。您的添加很好地显示了基本问题。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-02-12
          • 1970-01-01
          • 2012-12-05
          • 1970-01-01
          • 2015-01-08
          • 2014-07-14
          • 1970-01-01
          相关资源
          最近更新 更多