从静态函数调用非静态变量

7

我是一名初学者C ++程序员,正在为我的公司做一个PoC。因此,对于我的基础问题,我深表歉意。

class TestOne{
  private:
    TestTwo* t2;

  void createInstance(TestTwo* param){
    t2 = param;
  }

  static void staticFunctionToAccessT2(){
    // Now here I want to access "t2" here in the current instance of the class
    // By current instance I mean "this" in non-static context
    // currently there is no function to get object, but can be created
    // ** we cannot call new TestOne(), because that will create a new instance
    // ** of the current class and that I don't want.
  }
}

非常感谢您提供的帮助。

谢谢。

===更新内容===

这个场景可以被看作是我在QT Creator中开发应用程序的情况,我有一个预定义签名的静态函数,并想要访问UI元素以更改文本(如TextEdit)。


4
首先,这不是C++。其次,没有对象时访问某个特定对象的变量是毫无意义的。 - chris
很抱歉 Chris,实际上我是一名 Java 程序员,这就是为什么我出错了。我会更新代码示例的,感谢你指出问题。 - Jayesh
@Jayesh:T2在哪里?没有对象,你就无法访问对象。这个问题根本没有任何意义。 - Mike Seymour
@MikeSeymour 我正在使用的SDK不允许我放弃静态变量,也不允许我在参数列表中传递它,因为这个函数是预定义格式的。你能否提供一个替代方案? - Jayesh
@Jayesh:要么使用一个不那么糟糕的SDK——一个设计良好的回调类型应该为这种情况提供一个“用户数据”参数——要么将一个实例放在函数可访问的地方(可能是静态类成员),并且在函数仍然需要它时要非常小心,不要覆盖它。 - Mike Seymour
显示剩余2条评论
4个回答

3

即使在Java中,您也无法这样做。

static方法只是用于所有实例的本地帮助函数,不能访问单个类状态(例如t2)。

要么从方法中删除static,要么将成员变量设置为static变量,具体取决于您想要实现什么。

编辑:

如果我理解正确,您的SDK需要一个函数指针来修改实例的t2。您的mutator方法应该是public和非static。因此,让我们假设您像这样重新定义了staticFunctionToAccessT2

public: void mutateT2();

如果您想调用 mutateT2 的实例被定义为:
TestOne foo;

当您的SDK需要一个函数指针时,您可以传入以下内容:
std::bind(&TestOne::mutateT2, foo)

正如下面Mike Seymour所指出的,只有在SDK方法参数是std::function而不是裸函数指针时才适用。

如果它需要一个函数指针,那么你不能给它一个bind结果;那是一个类类型,包含了绑定的值,所以不能转换为简单的函数指针。如果它只接受函数指针,那么就没有办法传递额外的状态。 - Mike Seymour
@MikeSeymour 这取决于参数类型。例如,Qt的插槽接受std:function类型,该类型将接受std::bind的输出。我猜这就是Jayesh使用他的函数的原因。 - Jonathan Mee
实际上,如果参数类型是std::function或类似类型,则它将接受任何可调用对象。但是,如果它需要一个函数指针,则不能使用bind,这与您答案的最后一句话相反。 - Mike Seymour
@MikeSeymour 我已经为了正确性而编辑了答案。 - Jonathan Mee

0

可能有一种方法可以使用静态函数调用来设置类的非静态变量成员,但是只有在将同一类的引用传递给静态函数并访问非静态函数以设置非静态成员变量时才能实现。 但是再次强调,没有什么好的理由需要这样做。也许只是为了面试而已,我肯定可以说有一种方法可以做到这一点。 以下是执行相同操作的代码片段:

#include <iostream>
using namespace std;
class Test{
    int x;
    static int y;
    public:
        static void setY(int val){
            y = val;
        }
        void setX(int val){
            x = val;
        }
        static void setXY(int xval,int yval, Test& obj){
          obj.setX(xval);
            y = yval;
        }
        void display(){
            cout<<"x : "<<x<<", y: "<<y<<endl;
        }
};

int Test::y = 0;
int main()
{
    Test t;
    t.setY(10);
    t.setX(1);
    t.display();
    
    Test t1;
    t1.setX(100);
    t1.display();
    
    t1.setXY(1000,2000,t1);
    t1.display();


    return 0;
}

以上代码执行的输出: x:1,y:10 x:100,y:10 x:1000,y:2000
附带输出的代码片段: Code_Snippet_With_Output

0

没有“当前实例”; 在没有访问某个实例的情况下,您无法从静态函数中访问非静态成员。

根据您的评论,似乎您正在使用一个带有回调(或类似)机制的损坏API,该机制不会将用户数据传递给您提供的函数。在这种情况下,您将不得不找到其他方法将数据传递给函数; 也许是一个静态成员:

static TestOne * bodge;
static void staticFunctionToAccessT2(){
    TestTwo * t2 = bodge->t2;
}

因此API可以这样使用

TestOne::bodge = my_t1;
broken_api(&TestOne::staticFunctionToAccessT2);

注意在API完成对您的回调函数的操作之前,不要将bodge设置为其他值。

一个更好的API会定义一个回调类型,可以接受“用户数据”参数;也许是一个void*指针,它可以指向任意数据。您可以这样使用:

static void staticFunctionToAccessT2(void * p) {
    TestOne * t1 = static_cast<TestOne*>(p);
    TestTwo * t2 = t1->t2;
}

less_broken_api(&TestOne::staticFunctionToAccessT2, my_t1);

一个好的现代API应该接受任意可调用类型,这样你就可以使用非静态函数:
void memberFunctionToAccessT2() {
    TestTwo * t2 = this->t2;
}

nice_api([=]{my_t1->memberFunctionToAccessT2();});

0

静态成员函数没有“当前实例”。

如果您想将类限制为仅具有一个实例,则可以使用单例设计(反)模式C++中的单例模式。实际上,它并不那么恶劣,每当我使用具有静态成员变量的类时,我总是对它产生吸引力。

有许多方法可以使单例工作得更好,在此应该以RAII为主要目标,我在我的getInstance()静态方法中使用std::unique_ptr<TestOne> safeInstance;进行初始化,在我的Android环境中不存在异常情况。

如果您没有足够的经验需要问这个问题,我通常会建议您不要使用Singleton Pattern。但它似乎解决了您问题中的大部分问题。

此外,要调用非静态“变量”,我假设您指的是“方法”,则您的静态函数必须与您的单例实例一起工作,假设它已成功创建。它甚至可以通过单例实例访问非静态变量


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接