6

我编写了一个非常基本的表达式解析器,我希望它是可扩展的,因此它可以解析用户定义的表达式类型。例如,如果在解析时遇到字符<,我想创建一个用于解析以该字符开头的表达式的类的实例。

我有两个问题:

  1. 如何将字符关联到静态方法指针?

    我想使用一个静态方法来返回类的新实例,因为我无法获得指向类构造函数的指针。以下语法可能是错误的,但这就是想法:

    typedef static IValue * (*returnPtrIValue)();
    map<char, returnPtrIValue> ...
    
  2. 假设我有 A 类,B 类扩展 A 类,我可以初始化一个指向函数的指针,该函数返回指向 A 的指针/引用,并使用指向返回指向 B 的指针/引用的函数的指针,因为 B 是 A?

    例如,我可以这样做:

    typedef A * (*returnPtrA)();
    B * func() { ... }
    returnPtrA foo = func;
    
4

5 回答 5

3

1:static从您的 typedef 中删除,例如:

typedef IValue * (*returnPtrIValue)();

然后可以将指向静态成员函数的指针分配给该类型的变量(或放入映射中),例如:

returnPtrIValue fun = &SomeClass::somestaticfun;

这是你要求的吗?

2:一般来说 - 没有。至少不是以类型安全的方式。协方差在 C++ 中不起作用。

如果你真的想这样做,你可以reinterpret_cast使用联合或使用联合进行一些黑客操作,但这可能取决于编译器,我不建议这样做(如果你确实想要这个,我可以给你一些提示)。

更新: 这是一篇非常好的文章,它解释了如何借助 C++ 中的(成员)函数指针在 C++ 中实现委托。它深入研究了这个问题,我发现它的前半部分是 C++ 中(成员)函数指针以及如何使用它们的很好的参考/解释。如果您有兴趣了解它们在 C++ 中的工作方式,我建议您查看一下。

于 2013-05-26T11:46:21.303 回答
2

1)只需static从您的 typedef 中删除,“静态方法”就像一个简单的函数(仅在类的范围内声明)。

2)这似乎是合法的,但不幸的是我得到了一个编译器错误:

error: invalid conversion from 'B* (*)()' to 'A* (*)()'

似乎函数指针不支持协变返回类型......

于 2013-05-26T11:45:15.703 回答
1

如果您使用的是 C++11,则可以尝试以下操作:

#include <map>
#include <functional>
...
std::map<char, std::function<parser*()>> m;
m['a'] = []{return new parser_for_a;};

这样您就不需要任何静态方法。

于 2013-05-26T11:55:10.930 回答
0

此代码应回答您的问题,即使不完全正确。事实上,我通过virtual调用解决了你的一些问题(注意:性能问题)。

#include <iostream>
#include <map>


struct parse_result {
    // something here
};

class parser {
public:
    virtual parse_result parse() = 0;
};

class parser1 : public parser {
public:
    parse_result parse() {
        // something here
        std::cout << "Called parser1::parse()" << std::endl;
        return parse_result();
    }
};

class parser2 : public parser {
public:
    parse_result parse() {
        // something here
        std::cout << "Called parser2::parse()" << std::endl;
        return parse_result();
    }
};

static parser1* make_parser1() {
    return new parser1();
}

static parser2* make_parser2() {
    return new parser2();
}

typedef parser* (*parser_factory_method)();


int main() {

    std::map<char, parser_factory_method> parsers;
    parsers.insert(std::make_pair('1', (parser_factory_method) make_parser1));
    parsers.insert(std::make_pair('2', (parser_factory_method) make_parser2));

    for (auto entry : parsers) {
        std::cout << "Calling parser for " << entry.first << std::endl;
        parser_factory_method pfm = entry.second;
        parser* p = pfm();
        p->parse(); // parse_result is ignored here, but can be used as needed
        delete p;
    }

    return 0;

}

请注意,我不喜欢这种解析器设计。它以某种方式模仿 Java 反射,注定会出现性能问题。看看能不能细化。

于 2013-05-26T11:46:01.950 回答
0

这个线程帮助我做我想做的事:如何动态创建类对象? 感谢您的回答!

于 2013-05-26T14:09:03.447 回答