代码之家  ›  专栏  ›  技术社区  ›  Alan

C++类方法的指针

c++
  •  3
  • Alan  · 技术社区  · 18 年前

    在重构一些传统的C++代码时,我发现,通过某种方式定义一个变量,可以指向任何共享同一签名的类方法,可以潜在地删除某些代码复制。经过一番挖掘,我发现我可以做如下事情:

    class MyClass
    {
    protected:
        bool CaseMethod1( int abc, const std::string& str )
        {
            cout << "case 1:" << str;
            return true;
        }
    
        bool CaseMethod2( int abc, const std::string& str )
        {
            cout << "case 2:" << str;
            return true;
        }
    
        bool CaseMethod3( int abc, const std::string& str )
        {
            cout << "case 3:" << str;
            return true;
        }
    
    public:
        bool TestSwitch( int num )
        {   
            bool ( MyClass::*CaseMethod )( int, const std::string& );
    
            switch ( num )
            {
                case 1: CaseMethod = &MyClass::CaseMethod1;
                        break;
                case 2: CaseMethod = &MyClass::CaseMethod2;
                        break;
                case 3: CaseMethod = &MyClass::CaseMethod3;
                        break;
            }
    
            ...
    
            bool res = CaseMethod( 999, "hello world" );
    
            ...
    
            reurn res;
        }
    };
    

    我的问题是- 这是正确的方法吗? 我应该考虑什么吗? 促进 你必须提供什么?

    编辑

    好吧,我的错误-我应该这样调用该方法:

    bool res = ( (*this).*CaseMethod )( 999, "Hello World" );
    
    7 回复  |  直到 14 年前
        1
  •  8
  •   Anthony Williams    18 年前

    这里有一个指向成员函数的指针。它会解决你的问题。我很惊讶您的“TestSwitch”函数能够编译,因为调用语法与您可能期望的略有不同。应该是:

    bool res = (this->*CaseMethod)( 999, "hello world" );
    

    但是,您可能会发现boost::function和boost::bind的组合使事情变得更简单,因为您可以避免奇怪的调用语法。

    boost::function<bool(int,std::string)> f=
        boost::bind(&MyClass::CaseMethod1,this,_1,_2);
    

    this 指针:您可以使 如果愿意,成员函数的指针将显示第三个参数:

    boost::function<bool(MyClass*,int,std::string)> f=
        boost::bind(&MyClass::CaseMethod1,_1,_2,_3);
    

        2
  •  3
  •   Simon Steele    18 年前

    this->*Methods[num]( 999, "hello world" );
    

    这也会移除开关,并使清理更有价值。

        3
  •  1
  •   Paulius    18 年前

    您当然可以这样做,尽管CaseMethod调用是不正确的(它是指向成员函数的指针,因此您必须指定应该调用该方法的对象)。正确的调用如下所示:

    bool res = this->*CaseMethod( 999, "hello world" );
    

    boost::mem_fn -你把事情搞砸的机会就少了

        4
  •  1
  •   Vincent Robert    18 年前

    我看不出您的调用与在switch语句中简单调用方法之间的区别。

    不,没有语义或可读性差异。

    我看到的唯一区别是,您使用的是指向方法的指针,因此禁止编译器内联该方法或优化对该方法的任何调用。

        5
  •  1
  •   user3458 user3458    18 年前

    • 保持正常的switch语句,无需执行任何操作。这是最有可能的解决方案

    • 如@Simon所说,将指向成员函数的指针与数组结合使用,也可以与映射结合使用。对于包含大量案例的案例语句,这可能会更快。

    • 将类拆分为多个类,每个类都带有一个要调用的函数,并使用虚拟函数。这可能是最好的解决方案,购买它将需要一些严重的重构。考虑GOF模式,比如状态或访问者或者一些这样的模式。

        6
  •  0
  •   Nik    18 年前

    如果你只是按照你所描述的方式保留简单的指针,那么你就没问题了,但是在更复杂的使用之前,你可能想看看更通用的函子系统,比如 boost::bind

        7
  •  0
  •   Tyler    18 年前

    您可以定义一个抽象基类

    class Base { virtual bool Method(int i, const string& s) = 0; };
    

    然后将每个案例作为子类编写,例如

    class Case1 : public Base { virtual bool Method(..) { /* implement */; } };
    

    在某个时刻,您将获得指示要执行哪个测试的“num”变量。您可以编写一个接受这个num的工厂函数(我将它称为which_case),并返回一个指向Base的指针,然后从该指针调用方法。

    Base* CreateBase(int which_num) { /* metacode: return new Case[which_num]; */ }
    // ... later, when you want to actually call your method ...
    Base* base = CreateBase(23);
    base->Method(999, "hello world!");
    delete base;  // Or use a scoped pointer.
    

    顺便说一下,这个应用程序让我希望C++支持的静态虚拟函数,或者像“类型”之类的内置类型——但它不是。