用C ++完成这个任务;从AS3.0迁移

时间:2010-02-22 02:21:22

标签: c++ actionscript-3 migration

3 个答案:

答案 0 :(得分:1)

哇。

通过阅读慢慢地建议您最终想要的是一系列函数调用,您可以为不同的操作选择具有相同参数(但实现不同)的不同函数,并为正确选择正确的函数情况下。

如果是这种情况,那么你正在寻找函数指针。试试this tutorial

您应该能够使用带有参数集的函数指针,并根据您的需要将其指向正确的函数。你也不需要一个函数指针数组 - 任何与定义匹配的函数都应该这样做。在本教程中,声明一个像这样的函数指针:

int (TMyClass::*functptr)(classname, int, int) = NULL;                // C++

然后再分配:

this.functptr = &TMyClass::doitthisway; 

答案 1 :(得分:1)

您可以使用函数指针或仿函数存储函数。虽然C ++本身不支持变体类型,但您必须在那里使用自定义解决方案。

一种可能性是使用Boost.Any(或更好,Boost.Variant如果您只使用一组固定的类型):

typedef void (*Function)(Object*, const std::string&, boost::any&);
std::vector<Function> functions;

给定一些功能:

void f(Object* obj, const std::string& name, boost::any& value) {
    // ...
}

你可以存储和调用它类似于你的例子:

functions.push_back(&f);
functions[0](obj, "x", boost::any(500));

要使用声明性语法,我会想到三个选项:

  • 您使用类似的方法并具有中央“解释器”功能,例如基于开关(如果需要性能,不要忘记切换到整数或指向成员而不是字符串)
  • 您发明了自己的语言并从描述文件生成C ++代码
  • 以声明方式编写函数对象

要进行合成,您可以使用Boost.Bind或类似操作的自定义对象:

struct Operation {
    virtual ~Operation() {}
    virtual bool operator()(Object&) = 0;
};    

template<class T>
struct GreaterThen : Operation {
    typedef T Object::*Member;
    Member member;
    const T value;
    CompareGT(Member member, const T& value) : member(member), value(value) {}
    bool operator()(Object& obj) { return (obj.*member > value); }
};

template<class T>
struct SetTo : Operation {
    typedef T Object::*member;
    Member member;
    const T value;
    SetTo(Member member, const T& value) : member(member), value(value) {}
    bool operator()(Object& obj) { obj.*member = value; return true; }
};

现在我们可以构建操作列表:

typedef std::vector<Operation*> OpList;
OpList operation;
operations.push_back(new GreaterThen<int>(&Object::Frame, 64));
operations.push_back(new SetTo<int>(&Object::State, 1));

我们可以使用辅助函数来避免必须指定模板类型:

template<class T>
Operation* opGreaterThen(T Object::*mem, const T& val) {
    return new GreaterThen<T>(mem, val);
}

假设SetTo使用Boost.Assign并使用{{3}}的类似帮助,则上述内容变为:

OpList operations = boost::assign::list_of
    (opGreaterThen(&Object::Frame, 64)) 
    (opSetTo      (&Object::State,  1));

执行操作如下:

OpList::iterator it = operation.begin();
for( ; it != operations.end(); ++it) {
    Operation& op = *it; // just for readability
    if(!op(someObject)) break; // stop if operation returns false        
}

答案 2 :(得分:1)

虽然有可能(虽然很痛苦)拥有一个任意类型的数组,但你几乎从不需要它,因为你必须知道某些东西关于它在哪里做任何有趣的事情:例如,您的'TL; DR'示例看起来像:

struct AIRule {
    // Can only handle comparing ints, see later for more general solution.
    typedef bool compare_type(AIObject*, AIObject::*int, int);
    compare_type* compare;
    AIObject* object;
    AIObject::int* member;
    int comparand;
};

所以现在你可以这样做:

bool ai_equal(AIObject* object, AIObject::int* member, int comparand) {
    return object->*member == comparand;
}

...
    ai[n].compare = &ai_equal;
    ai[n].object = some_object;
    ai[n].member = &AIObject::some_member;
    ai[n].comparand = 50;
...
    if (ai[n].compare(ai[n].object, ai[n].member, ai[n].comparand)) {
        ...
    }

这只是将任何类型的问题从rules数组移到member。 C ++需要知道一个成员至少有多少字节,一个字符串(例如)可以比一个大得多。你可以通过使用指针解决这个问题:这本质上是C ++的任何版本,但你需要自己删除它(或者你会泄漏内存!),此时下面的接口方法变得更简单。

如果我正在做你想要的事情,我会使用继承:

struct Sprite {
    int frame;
    double rotation;

    Sprite() {
        frame = 0;
        rotation = 0.0;
    }
    virtual ~Sprite() {}

    virtual void think() {
        ++frame;
    }

    virtual void draw() {
        ...
    }
};

struct RotatingSprite : public Sprite {
    int state;

    MyShape() {
        state = 0;
    }

    void think() {
        Sprite::think();
        if (state == 0 && frame > 64) {
            state = 1;
            rotation += 180.0;
        }
    }
};

或函数指针:

struct Sprite {
    int frame;
    double rotation;
    void (*think)(Sprite*);

    Sprite() {
        frame = 0;
        rotation = 0.0;
    }
};

void rotate_think(Sprite* sprite) {
    if (sprite->state == 0 && sprite->frame > 64) {
        sprite->state = 1;
        sprite->rotation += 180.0;
    }
}

...
    sprite->think = &rotate_think;

如果你真的需要动态地做,我建议使用C ++的++部分。对于谓词(谓词只是返回布尔值的东西,如isLowerCase())创建AIPredicate接口,以及AIAction接口的操作:

struct AIPredicate {
    // "When you delete an AIPredicate, delete the full type, not just this interface."
    virtual ~AIPredicate() {}
    // "You can treat this as a function (operator()) but I'm not providing an implementation here ( = 0)"
    virtual bool operator()(AIObject* object) = 0;
};

struct AIAction {
    virtual ~AIAction() {}
    virtual void operator()(AIObject* object) = 0;
};

struct AIRule {
    // std::auto_ptr (or std::unique_ptr if you can use C++0x) will delete predicate for you.
    // Add "#include <memory>" to your includes if it complains (most std headers will include it already)
    std::auto_ptr<AIPredicate> predicate;
    std::auto_ptr<AIAction> action;
};

现在你可以制作如下类型:

struct AIFrame : public AIPredicate {
    // Implement the operator() member AICondition promises.
    bool operator()(AIObject* object) {
        return object->foo < 100;
    }
};

...
    // Use .reset() instead of = if you use std::unique_ptr.
    ai[n].predicate = new AIFooIsLow();

如果你想拥有一个非常通用的谓词类型,你可以使用非常强大(和复杂)的模板功能:

// The naming convention I'm using here is 'T'TitleCase for template parameters, TitleCase for types,
// lower_case for arguments and variables and '_'lower_case for members.
template<typename TMemberType, AIObject::TMemberType* TMember>
struct AIMemberEquals : public AIPredicate {
    // Constructor: Initializes a new instance after it is created.
    AIMemberEquals(TMemberType comparand) {
        // Save comparand argument so we can use it in operator().
        _comparand = comparand;
    }

    bool operator()(AIObject* object) {
        return object->*TMember == comparand;
    }
    // Stores the value to compare.
    TMemberType _comparand;
};

不幸的是,创建模板看起来有点疯狂:

ai[n].predicate = new AIMemberEquals<int, &AIObject::some_member>(100);

将其读作“创建一个新实例(AIMemberEquals应用于int的类型和(AIObject的some_member成员)创建的类型),参数为100”。

当你有多个谓词时,如果没有C ++ 0x的unique_ptr或shared_ptr,内存管理会变得有点困难,因为std :: auto_ptr在容器中不起作用,因此会删除对象的类型:

#include <vector>

struct AIData {
    // vector is fairly close to AS3's Array type, it is a good default for
    // arrays of changing or unknown size.
    std::vector<AIPredicate*> predicates;

    // Destructor: will be run before the memory for this object is freed.
    ~AIData() {
        for (int i = 0; i != predicates.size(); ++i) {
            delete predicates[i];
        }
    }
};

...
    ai[n].predicates.push_back(new AIFooIsLow());
...
    for (int i = 0; i != ai[n].predicates.size(); ++i) {
        (*ai[n].predicates[i])(ai[n].object);
    }

在C ++ 0x中:

struct AIData {
    // unique_ptr will delete it for you, so no ~AIData() needed.
    std::vector<unique_ptr<AIPredicate>> predicates;
};

你最后的例子可能在C ++中看起来像:

std::auto_ptr<Shape> shape(new Shape());
...
std::auto_ptr<AIRule> rule(new AIRule());

rule->predicates.push(new AIMemberEquals<int, &Shape::state>(0));
rule->predicates.push(new AIMemberGreater<int, &Shape::frame>(64));

rule->actions.push(new AIAddMember<double, &Shape::rotation>(180.0));
rule->actions.push(new AISetMember<int, &Shape::state>(1));

shape->ai.push(rule); // .push(std::move(rule)); if you are using unique_ptr

当然不是那么漂亮,但它有效且相当灵活。