方法中需要访问的多个结构,相同字段 [英] Multiple structs, same fields that need to be accessed in a method

查看:85
本文介绍了方法中需要访问的多个结构,相同字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在尝试编写一些Lil文字游戏机,以在C中获得乐趣.

I currently try to write some lil literal console game for fun in C.

为此,我需要能够在...井... C中打印类似窗口的结构.

For that, i need to be able to print window-like structures in ... well ... C.

我想使用一种通用的渲染方法(称之为frame_render(...))来渲染所有不同的"ui元素"

I want to use a generic rendering method (lets call it frame_render(...)) to render all different "ui elements"

现在的问题是:如何解决这个问题?

The problem now is: how to solve this?

鉴于这种情况:

// Theoretical base
struct frame { int x; int y; int width; int height; }
struct button { int x; int y; int width; int height; ... }
struct whatever { int x; int y; int width; int height; ... }

我如何确保我的xywidthheight始终位于正确的点内存中? 刚开始时以仅"顺序排列它们就足够了吗?

how could i ensure that my x, y, width and height are always in the correct spot memory wise? is it enough to "just" put them in the same order at the very begining?

还,如何设计方法标题以接受它?

also, how to design the method header to accept it?

推荐答案

刚开始时以仅"顺序排列它们就足够了吗?

is it enough to "just" put them in the same order at the very begining?

是的,如果您像上面那样谨慎的话.

Yes, if you're careful as you've done above.

还,如何设计方法标题以接受它?

also, how to design the method header to accept it?

执行此操作的方法有多种.

There are different ways to do this.

下面是一个示例,它使用c++基础"类的[ugly]等效项:

Here's an example, using the [ugly] equivalent of a c++ "base" class:

enum type {
    FRAME,
    BUTTON,
    WHATEVER
};

struct geo {
    int x;
    int y;
    int width;
    int height;
    enum type type;
};

struct frame {
    struct geo geo;
};

struct button {
    struct geo geo;
    int updown;
};

struct whatever {
    struct geo geo;
    int what;
    int ever;
};

void
frame_render(struct geo *geo)
{
    struct frame *frm;
    struct button *but;
    struct whatever *what;

    switch (geo->type) {
    case FRAME:
        frm = (struct frame *) geo;
        frame_render_frame(frm);
        break;

    case BUTTON:
        but = (struct button *) geo;
        printf("x=%d y=%d updown=%d\n",geo->x,geo->y,but->updown);
        frame_render_button(but);
        break;

    case WHATEVER:
        what = (struct whatever *) geo;
        printf("x=%d y=%d what=%d ever=%d\n",
            what->geo.x,what->geo.y,what->what,what->ever);
        frame_render_whatever(what);
        break;
    }
}

这是使用虚函数表的一种方法:

Here's a way to use a virtual function table:

enum type {
    FRAME,
    BUTTON,
    WHATEVER
};

struct geo;

// virtual function table
struct virtfnc {
    void (*calc)(struct geo *);
    void (*render)(struct geo *);
};

struct geo {
    int x;
    int y;
    int width;
    int height;
    enum type type;
    struct virtfnc *fnc;
};

struct frame {
    struct geo geo;
};

struct button {
    struct geo geo;
    int updown;
};

struct whatever {
    struct geo geo;
    int what;
    int ever;
};

void
frame_render(struct geo *geo)
{
    struct frame *frm = (struct frame *) geo;

    // whatever
}

void
button_render(struct geo *geo)
{
    struct button *but = (struct button *) geo;

    // whatever
}

void
whatever_render(struct geo *geo)
{
    struct whatever *what = (struct whatever *) geo;

    // whatever
}

void
any_render(struct geo *geo)
{

    geo->fnc->render(geo);
}

这是使用union的第三种方式.它比较简单,但是要求基本结构必须与最大的子类一样大:

Here's a third way that uses a union. It is simpler but requires that the base struct be as large as the largest sub-class:

enum type {
    FRAME,
    BUTTON,
    WHATEVER
};

struct frame {
    ...
};

struct button {
    int updown;
};

struct whatever {
    int what;
    int ever;
};

struct geo {
    int x;
    int y;
    int width;
    int height;
    enum type type;
    union {
        struct frame frame;
        struct button button;
        struct whatever what;
    } data;
};

void
any_render(struct geo *geo)
{

    switch (geo->type) {
    case FRAME:
        render_frame(&geo->data.frame);
        break;

    case BUTTON:
        render_button(&geo->data.button);
        break;

    case WHATEVER:
        render_whatever(&geo->data.what);
        break;
    }
}


更新:

这种方法投放安全吗?例如.将所有内容放入类型为frame*的某个数组中,然后仅访问frame->geo吗?还是对以后调用free(..)造成任何问题?

is this approach casting safe? eg. putting all into some array that is of the type frame* and then just accessing frame->geo? or would that cause any problems with later calls to free(..)?

如果使用派生的类型(例如framebutton)进行分配,但不是基本类型geo,则free没问题:malloc(sizeof(struct button)).

No problem with free if allocations are done with the derived types (e.g. frame, button), but not the base type geo: malloc(sizeof(struct button)).

要拥有一个[形状]的简单数组,需要使用union方法(即,所有派生的结构必须具有相同的大小).但是,如果我们有一些子类型比其他的使用了 lot 个更多的空间,这将是浪费的:

To have a simple array [of shapes], the union method would need to be used (i.e. all derived structs must have the same size). But, this would be wasteful if we had some subtype that used a lot more space than the others:

struct polyline {
    int num_points;
    int x[100];
    int y[100];
};

仍然可以使用方法#1或#2 [其中子类型结构的大小不同]和间接指针数组来完成 :

This could still be done with methods #1 or #2 [where the subtype structs are of different sizes] with an indirect pointer array:

void
all_render(struct geo **glist,int ngeo)
{

    for (;  ngeo > 0;  --ngeo, ++glist)
        any_render(*glist);
}

我会考虑使用一个[双重]链接列表,而不是使用不同形状的数组.这允许子类型结构具有不同的大小.我们将struct geo *next元素添加到struct geo.然后,我们可以这样做:

Rather than an array of different shapes, I'd consider a [doubly] linked list. This allows the subtype structs to have different sizes. We'd add a struct geo *next element to struct geo. Then, we could do:

void
all_render(struct geo *geo)
{

    for (;  geo != NULL;  geo = geo->next)
        any_render(geo);
}

列表方法可能更可取,特别是如果我们动态添加/删除形状(或基于Z深度重新排列形状).

The list approach may be preferable, particularly if we add/remove shapes on a dynamic basis [or reorder them based on Z-depth].

或者,某些形状可能包含其他形状.因此,我们可以将struct geo *children添加到struct geo.然后,很容易(例如)绘制一个包含框,然后遍历children列表,然后绘制该框中的所有形状.如果我们选择children,我们也可以添加struct parent *parent,以便每个形状都知道包含它的形状.

Or, some shapes might contain others. So, we could add struct geo *children to struct geo. Then, it's easy to (e.g.) draw a containing box, then all the shapes within that box by traversing the children list. If we go for children, we may as well add struct parent *parent as well so each shape knows what shape contains it.

这篇关于方法中需要访问的多个结构,相同字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆