c ++如何在类成员之间实现切换

时间:2016-11-16 04:37:45

标签: c++

我对c ++很陌生,所以我想知道如何在c ++中以正确的方式做事。我正在上一个使用两个成员之一的课程。哪一个在实例化时得到确定。它看起来像

main() {
    shared_pointer<A> a = make_shared<A>(); 
    if ( checkSomething ) { 
        a->setB(make_shared<B>()); 
    } else {
        a->setC(make_shared<C>()); 
    }
    a->doStuff();

class A {
    public:
        doStuff() {

        /*here I want to do something like call 
        m_b->doStuff() if this pointer is set and m_c->doStuff() if 
        that pointer is set.*/

       }

        setB( B* p ) { m_b = p; }
        setC( C* p ) { m_c = p; }
        B* m_b;
        C* m_c;
    }
}
B and C are some classes with doStuff() member function

像doStuff这样的成员很多。理想情况下,我会避免在每个中检查nullptr。在这两个成员之间创建切换的最佳/最有效/最快的方法是什么?

有没有办法使用静态指针,以便我有一个成员

static **int m_switch;

并执行类似

的操作
m_switch = condition ? &m_b : &m_c;

并致电

*m_switch->doStuff();

这里的编译器是否也替换额外的指针跳,因为它是静态的?

还有其他智能方法可以做这些开关吗?

4 个答案:

答案 0 :(得分:4)

通常,类A将是接口类,BC都将继承和实现。但听起来你出于某种原因无法做到这一点。

由于你想模仿这个,你可以先创建界面:

class A_interface
{
public:
    virtual void doStuff() = 0;
    virtual void doThings() = 0;
    virtual void doBeDoBeDo() = 0;
};

然后你制作一个模板包装器:

template< class T >
class A : public A_interface
{
public:
   void doStuff() override { target.doStuff(); }
   void doThings() override { target.doThings(); }
   void doBeDoBeDo() override { target.doBeDoBeDo(); }

private:
    T target;
};

这基本上是您自己的示例类A尝试执行的操作的一半,但现在您可以使用通用接口。您需要做的就是构建所需的正确模板版本:

std::shared_ptr<A_interface> a;

if( checkSomething ) {
    a = std::make_shared<A<B>>();
} else {
    a = std::make_shared<A<C>>();
}

a->doStuff();

答案 1 :(得分:1)

对于您的问题,没有一个通用的解决方案。使用方法取决于您的具体问题。一些可能的答案:

  • 接口
  • 策略模式
  • 指针(用于保存实现doStuff的函数或类)

界面就像合约。从接口继承的任何类都必须实现其成员。例如,

class IDoesStuff
{
public:
    virtual ~IDoesStuff() {};
    virtual void DoStuff() = 0;
};

现在可以被其他类使用:

class Foo : public IDoesStuff
{
public:
    virtual void DoStuff()
    {
        // ....
    }
};

class Bar : public IDoesStuff
{
public:
    virtual void DoStuff()
    {
        // ....
    }
};

现在,一般情况下,人们可以这样做:

Foo foo;
IDoesStuff *stuffDoer= &foo;

stuffDoer->doStuff();

这可以在您的特定用例中使用,如下所示:

class A
{
    IDoesStuff *stuffDoer; // Initialize this at some point.

public:
    void doStuff() { stuffDoer->doStuff(); }
};

答案 2 :(得分:1)

您需要让两个成员都实现一个通用接口,以便类似地使用它们。但为了做到这一点,您需要定义接口并将调用中继到B和C类。

// existing classes
class B
{
public:
  void doStuff() { std::cout << "B"; }
};

class C
{
public:
  void doStuff() { std::cout << "C"; }
};

// define your interface
class I
{
public:
  virtual void doStuff() = 0;
};

// new classes
class D : public B, public I
{
public:
  void doStuff() override { B::doStuff(); }
};

class E : public C, public I
{
public:
  void doStuff() override { C::doStuff(); }
};

// your A class
class A
{
public:
  D* b = nullptr; // now type D
  E* c = nullptr; // now type E

  // your toggle
  I* getActive()
  {
    if (b)
      return b;
    else
      return c;
  }

  // simple doStuff() function
  void doStuff()
  {
    getActive()->doStuff();
  }
};

int main()
{
  A a;
  if (true)
    a.b = new D; // need to initialize as D
  else
    a.c = new E; // need to initialize as E

  a.doStuff(); // prints B
}

但输入此内容后,我意识到定义DE可能会让您感到非常厌烦,并且反对您尝试保存的内容。但是,您可以定义一个模板来创建它们,就像@paddy所做的那样。

答案 3 :(得分:1)

首先,您必须将您的memebr变量m_bm_c更改为std::shared_ptr

添加类型std::function(void())的成员变量以保存要调用的目标函数。在您的示例中,它是do_stuf

在你的setter函数中,你可以将目标函数绑定到std::functiondo_stuf,只需调用std::function

(您需要一个C ++ 11编译器)

class B
{
public:
    void doStuff() 
    {
    }
};

class C
{
public:
    void doStuff()
    {
    }
};

class A 
{
public:
    void doStuff() 
    {
        m_target_function();
    }

    void setB(std::shared_ptr<B> p)
    {
        m_b = p;

        m_target_function = std::bind(&B::doStuff, m_b.get());
    }
    void setC(std::shared_ptr<C> p)
    {
        m_c = p;

        m_target_function = std::bind(&C::doStuff, m_c.get());
    }

    std::shared_ptr<B> m_b;
    std::shared_ptr<C> m_c;

    std::function<void()> m_target_function;
};

int _tmain(int argc, _TCHAR* argv[])
{
    std::shared_ptr<A> a = std::make_shared<A>();

    bool use_B = false;

    if (use_B) 
    {
        a->setB(std::make_shared<B>());
    }
    else 
    {
        a->setC(std::make_shared<C>());
    }

    a->doStuff();
}