C语言中的"this"指针(非C++)

17
我正在尝试为了好玩而在C语言中创建一个栈,并想到使用结构体来表示栈。然后我向结构体添加了函数指针以进行push()和pop()操作。
目前似乎一切都很好,但是为了实现push()和pop()函数,我需要以某种方式引用*this。那么如何做到这一点呢?这是我的结构体:
struct Stack {
    int *data;
    int current_size;
    int max_size;
    int (*push)(int);
    int (*pop)();
};

这里有一个示例,展示如何进行push操作

int push(int val) {
    if(current_size == max_size -1)
            return 0;

    data[current_size] = val;
    current_size++;

    return 1;
}

你可以想象,编译器并不知道 current_size 是什么,因为它预期的是像 stack->current_size 这样的东西。

有没有办法解决这个问题呢?


你的栈结构中使用函数指针有什么意义? - Nyan
尝试回答是否可以像这样调用此类型的堆栈:stack->push(10);。如果在这里没有得到答案,我可以相当自信地说它确实是不可能的。 - foo
7个回答

29

C语言中没有隐式的this关键字,需要显式使用:

int push(Stack* self, int val) {
    if(self->current_size == self->max_size - 1)
            return 0;

    self->data[self->current_size] = val;
    (self->current_size)++;

    return 1;
}

当然,您必须在每次调用push和类似方法时传递指向struct的指针。

当您将Stack定义为一个类并将push等定义为方法时,这基本上就是C++编译器为您执行的操作。


3
这就是想表达的意思,但是在C++程序中使用this作为变量会让人感到尴尬。 - Victor Nicollet
我可以这样做,但是在结构体中使用指针函数就没有意义了。如果可能的话,我想直接调用 push(int val) ,即使会很丑陋。如果答案是无法实现,那么也是令人满意的答案。 - foo
2
除了“this”之外,将C代码包含在C++源文件中不是有效的,可能会导致重大错误。不要这样做。如果“this”作为变量名有意义(正如此处所示),请使用它。 - R.. GitHub STOP HELPING ICE
2
@foo:在结构体中放置函数指针仍然有一定的意义。你不应该使用如pushpop这样通用的名称来声明外部函数,特别是如果代码最终可能成为库的一部分。因此,你需要将它们命名为foo_pushfoo_pop之类的名称,或者在堆栈的实现文件中将它们隐藏为static,并使foo_allocstack返回一个带有函数指针设置为指向这些静态函数的堆栈对象。后一种解决方案具有更多的开销,但它可能是有用的。 - R.. GitHub STOP HELPING ICE

4

C语言中的典型方法是让函数将this作为第一个参数。

int push(Stack *self, int val) 
{
  if (self->current_size == self->max_size -1) return 0;
  self->data[self->current_size++] = val;
  return 1;
}

这样做的好处是,除非你需要多态性,否则你不需要将函数放在堆栈中,因为你可以直接调用 push(stack, 10) 而不是 stack->push(stack,10)


谢谢。那是我的第一种方法,但我想通过函数指针来寻找乐趣,并想看看C语言能够实现多少类似于C++的行为。这样做的目的是为了自我教育和实验,没有什么严重的意义。我同意在C语言中使用push(stack, 10)是最明智的选择。 - foo

2
在头文件中,您可以声明static this变量。
static struct Stack *this;

然后在push方法中,您可以使用this变量。
static int push(int val) {
    if(this->current_size == this->max_size - 1)
            return 0;

    this->data[this->current_size] = val;
    (this->current_size)++;

    return 1;
}

需要注意的是,在调用其他方法之前,您必须通过某种方法手动设置this变量,例如:

struct Stack {
    struct Stack (*_this)(struct Stack *); // <-- we create this method
    int *data;
    int current_size;
    int max_size;
    int (*push)(int);
    int (*pop)();
};

然后我们可以实现_this方法如下:
static struct Stack *_this(struct Stack *that)
{
    retrun this = that;
}

例子:

struct Stack stack1, stack2;

... some initialization ...

stack1->_this(&stack1)->push(0);
stack1->push(1);
stack1->push(2);

stack2->_this(&stack2);
stack2->push(10);
stack2->push(20);

跟踪指针当前指向的内容。 - septianw

1

C语言不是面向对象的语言,所以它不是这样工作的。操作数据结构的函数需要将指向该结构的指针作为参数。


0

你的函数指针不是方法,因此它们没有关于调用对象的任何信息。实现你想要的唯一方法是传递一个指向对象的指针,或者将该指针设置为全局变量(后者不建议使用)。


-1
显然,您可以在结构体中拥有一个Stack *成员,然后在使用函数指针之前将其初始化为结构体的地址。然后将Stack *作为函数指针的参数。

6
你刚刚把钥匙锁在了车里。 - Victor Nicollet
那似乎很明显。我没想到过,一定要试试看。谢谢。 - foo
我在想这个网站上的不同用户是否会比其他人先看到问题。我不知道像这样的问题怎么可能在不到一分钟内就得到四个答案。 - ThomasMcLeod
@foo - 使用这种解决方案,您仍然面临完全相同的问题 - 推送和弹出指向的函数不知道调用对象的任何信息。 - Niki Yoshiuchi
实际上没有什么好的理由将Stack*作为结构体的成员。需要将结构体地址传递到通过指针调用的函数中。 - ThomasMcLeod
显示剩余2条评论

-2

由于您只会有一个名为stackStack结构,因此可以将其定义为全局变量。这将允许pop/push直接引用stack变量。

您可以这样做:

stack.current_size += 4;

或者如果您决定将stack声明为指向Stack的内存指针,则可以使用->运算符。


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