C++ 成员函数的抽象指针:安全性和替代性

C++ 成员函数的抽象指针:安全性和替代性,c++,c++11,member-function-pointers,C++,C++11,Member Function Pointers,在这个问题中,假设我们以一种友好、谨慎的方式处理了所有指针——为了防止问题膨胀,我不想在这里包含我的清理代码 假设我们有两个类,Foo和Bar,类定义如下: class Foo { public: Foo(); void fooFn(); }; class Bar { public: Bar(); void barFn(); }; 假设Foo和Bar没有继承关系是必要的,但是我们需要调用fooFn和barFn,以

在这个问题中,假设我们以一种友好、谨慎的方式处理了所有指针——为了防止问题膨胀,我不想在这里包含我的清理代码

假设我们有两个类,
Foo
Bar
,类定义如下:

class Foo
{
    public:
        Foo();
        void fooFn();
};

class Bar
{
    public:
        Bar();
        void barFn();
};
假设
Foo
Bar
没有继承关系是必要的,但是我们需要调用
fooFn
barFn
,以响应某些刺激。我们可以创建一个带有容器的控制器类,从中调用
fooFn
barFn
,对
Foo
Bar
的特定实例进行调用,例如静态
std::vector
,但我们遇到了一个问题:指向
Foo
Bar
实例的成员函数的指针是不同的类型

通过在控制器类中使用静态
向量
,我们可以找到一个解决方法
Foo
Bar
实例可以有一个函数,该函数通过lambda函数向向量添加指针,lambda函数捕获

void Foo::registerFnPointer()
{
    ControllerClass::function_vector.push_back( new [this](){ return this->fooFn(); } );
}

我已经测试了这个方法,它似乎没有任何问题。这就是说,我担心的问题,可能会造成规避类型差异之前提到。。。我什么都不担心吗?有没有更好的方法来实现等效功能?

我看到的唯一问题实际上与函子无关,而是与对象生命周期有关。也就是说:我不知道如何确保每当Foo或Bar实例被销毁时,总是取消注册向ControllerClass注册的函子

然而,您提到您进行了适当的内存管理

在我看来,您不需要存储指向
函数的指针
,只需将函数存储为值(即具有
向量

在C++11和lambdas之前,为了达到相同的效果,您还将使用(boost)函数,但您将使用boost::bind,其中包含fooFn的地址和绑定到指向Foo对象实例的指针(或引用)的第一个参数

这将创建一个函数实例,该实例保存在给定对象上调用fooFn方法所需的所有信息。然后,您可以将实例存储在一个向量中,以便稍后调用它(同样的问题是确保绑定到已销毁对象的no
boost::function
保持注册状态)

编辑:

为完整起见,指向特定于绑定成员的Boost bind文档的链接:

您所做的实际上非常类似,只是现在使用lambda捕获对象指针并定义要调用的函数


因此,我认为您所做的没有问题(除了我已经提到的那一个)。

您可以使用适配器类。这对你正在做的事情来说可能是过分的,但它可能会起作用

这样做的好处是:

  • 您不必更改原始类。创建
    void Foo::registernPointer()
    很难看

  • 您不必使用静态
    std::vector

  • 您不必处理函数指针

  • 假设有两个不同的类,如下所示:

    struct Foo
    {
        void fooFn () { 
            std::cout << "Foo::fooFn ()" "\n" ; 
        }
    };
    
    struct Bar
    {
        void barFn () {
            std::cout << "Bar::barFn ()" "\n" ; 
        }
    };
    
    struct Adapter_Base
    {
        virtual ~Adapter_Base () {} ;
    
        virtual void adapterFn () = 0 ;
    };
    
    template <typename T>
    struct Adapter : Adapter_Base
    {
        T tVal ;
    
        Adapter (const T &tVal) : tVal (tVal) {}
        void adapterFn () ;
    };
    
    template <>
    void Adapter <Foo>::adapterFn ()
    {
        tVal.fooFn () ;
    }
    
    template <>
    void Adapter <Bar>::adapterFn ()
    {
        tVal.barFn () ;
    }
    
    int main ()
    {
        std::vector <std::unique_ptr <Adapter_Base> > v1 ;
    
        std::unique_ptr <Adapter_Base> u1 (new Adapter <Foo> (Foo ())) ;
        std::unique_ptr <Adapter_Base> u2 (new Adapter <Bar> (Bar ())) ;
    
        v1.push_back (std::move (u1)) ;
        v1.push_back (std::move (u2)) ;
    
        for (auto &adapter : v1) {
            adapter->adapterFn () ;
        }
    
        return 0 ;
    }
    
    你可以这样使用它:

    struct Foo
    {
        void fooFn () { 
            std::cout << "Foo::fooFn ()" "\n" ; 
        }
    };
    
    struct Bar
    {
        void barFn () {
            std::cout << "Bar::barFn ()" "\n" ; 
        }
    };
    
    struct Adapter_Base
    {
        virtual ~Adapter_Base () {} ;
    
        virtual void adapterFn () = 0 ;
    };
    
    template <typename T>
    struct Adapter : Adapter_Base
    {
        T tVal ;
    
        Adapter (const T &tVal) : tVal (tVal) {}
        void adapterFn () ;
    };
    
    template <>
    void Adapter <Foo>::adapterFn ()
    {
        tVal.fooFn () ;
    }
    
    template <>
    void Adapter <Bar>::adapterFn ()
    {
        tVal.barFn () ;
    }
    
    int main ()
    {
        std::vector <std::unique_ptr <Adapter_Base> > v1 ;
    
        std::unique_ptr <Adapter_Base> u1 (new Adapter <Foo> (Foo ())) ;
        std::unique_ptr <Adapter_Base> u2 (new Adapter <Bar> (Bar ())) ;
    
        v1.push_back (std::move (u1)) ;
        v1.push_back (std::move (u2)) ;
    
        for (auto &adapter : v1) {
            adapter->adapterFn () ;
        }
    
        return 0 ;
    }
    
    int main()
    {
    std::向量v1;
    std::unique_ptr u1(新适配器(Foo());
    std::unique_ptr u2(新适配器(Bar());
    v1.push_back(标准::move(u1));
    v1.push_back(标准::移动(u2));
    用于(自动和适配器:v1){
    适配器->适配器fn();
    }
    返回0;
    }
    
    这些都不是。为什么
    vector
    而不是简单的
    vector
    ControllerClass::function\u vector.push\u back([this]{return fooFn();})?@您称之为类声明。转发声明将是
    类Foo。我想你可以说你用正向声明成员函数来声明类,但是对于函数来说更常见的是声明和定义。你也可以用
    std::bind
    。他现在所做的一切还可以。函数实际上执行的是适配器所执行的操作(它保留要调用的实例和函数)。代码要少得多。他实际上是在问他所做的是否可以,是否有更好的方法来完成同样的事情。我不认为你的建议是更好的解决方案。@ds27680在OP的帖子中,他在每个类中添加了一个新的成员函数。这样做,您不必更改原始类。您也不必处理使用静态向量或函数指针的问题,但是适配器并没有解决新成员函数的“问题”。您只需将他在RegisternPointer中编写的代码移动到main。他选择用一种新的课堂方法进行注册(即使有争议),这与他的问题没有多大关系。他本可以编写与您在main中编写的代码相同的代码(我指的是等效代码)。解决静态向量问题也是如此。您将向量移到了main…这只是std::function的一个糟糕的重新实现。我看不出答案中C++11之前部分的要点。问题被标记为C++11,但在我看来,这里唯一的C++11细节是std::function现在是STL和lambda的一部分。他的问题实际上是C++11独立的。。。我还想说,他正在做的事情不是以前做不到的。同时要说的是:旧的做事方式很好(没有问题)。新的方式(你正在做的)实际上几乎是一样的->而且很好。。。同时也描述了实现同样目标的另一种方法。谁知道呢,如果有人不能切换到最新版本的支持C++11的编译器,他可能会在某个时候对此表示感谢。