1

免责声明我不允许使用 BOOST 或任何其他库,只能使用标准库。

在我的类Foo中,我有一个模板函数foo,它有两个参数:一个指向对象的指针和一个指向这个对象成员函数的指针。foo如您所见,该函数适用于任何类的指针。我不知道,什么类将传递给它。此函数创建模板结构的实例。

template <typename TypeName>
struct Bar
{
    void(TypeName::*action)();
    TypeName* objPtr;
};



template <typename TypeName> void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr )
{
    Bar <TypeName> bar;
    bar.action = action;
    bar.objPtr = objPtr;
};

我的问题是:如何存储Bar, created in 的对象foo,以便以后可以遍历它们并像这样调用指向对象成员函数的指针:

(BarStorage[i].objPtr->*BarStorage[i].action)();
4

1 回答 1

5

使用类型擦除

class BarBase {
    virtual void invoke() = 0;
};

template<typename TypeName>
class Bar final : public BarBase {
    void(TypeName::*action)();
    TypeName* objPtr;
    virtual void invoke() override { (objPtr->*action)(); }
};

class Foo {
    std::vector<std::unique_ptr<BarBase>> myBars;
/* ... */
};

template <typename TypeName>
void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr)
{
    auto bar = new Bar<TypeName>();
    bar->action = action;
    bar->objPtr = objPtr;
    myBars.emplace_back(bar);
};

然后只需调用myBars[x]->invoke();


回答评论中的问题。

怎么了override明确地说您从基类中重写虚函数。这在这里并不是真正必要的,但被认为是良好的做法。有关更多详细信息,请参阅Wikipedia 文章

它是 C++11 的一个新特性,一些编译器在很长一段时间内都以某种方式支持这个特性,但它直到现在才被标准化。GCC 应该从 4.7 版本开始支持这个特性——你必须使用命令行参数-std=c++0x

怎么了unique_ptr它使生活更轻松。当您分配时new Bar<XXX>(),您必须在某个时候说delete释放该内存。如果您将指针放在像 之类的资源管理对象unique_ptr中,则不再需要担心删除它。你将vector<BarBase*>不得不声明一个析构函数,Foo它执行以下操作:

for each element in myBars
    delete element

如果您使用vector<unique_ptr<BarBase>>,则无需担心删除任何内容。当在 的生命vector结束时被销毁时Foo,它将销毁其元素 - 并unique_ptr删除它包含在自己的析构函数中的内存。

这也是 C++11 的特性——标准库的补充。您不必使用它(但请确保最后删除所有内容)。

怎么了auto而不是重复相同的类型两次(Bar<Type> * bar = new Bar<Type>();),只需使用一次,然后让编译器根据初始化程序的类型推断出变量的正确类型。它的行为完全相同,只是打字更少,看起来更好:)

还有 C++11 特性,自 v4.4 起在 GCC 中得到支持。

为什么myBars[x]->invoke()做对的事?因为invokeBarBase. 这意味着执行的方法是根据 的动态类型(执行期间的实际类型)而myBars[x]不是静态类型来选择的。有关深入解释,请参阅Wiki。这种机制有一点运行时开销,但在处理动态类型时无济于事。

于 2012-08-28T11:31:14.830 回答