Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ how to implement a switch between class members

Tags:

c++

I am very new to c++ so I am trying to get a feeling of how to do things the right way in c++. I am having a class that uses one of two members. which one gets determined at instantiation. It looks something like

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

There are many members like doStuff. Ideally I would avoid checking for nullptr in each of them. What is the best/most efficient/fastest way to create a switch between those two members?

Is there a way to use a static pointer so that I have a member

static **int m_switch;

and do something like

m_switch = condition ? &m_b : &m_c;

and call

*m_switch->doStuff();

Does the compiler here also replace the extra pointer hop because it is a static?

Is there any other smart way to do those switches?

like image 998
chrise Avatar asked Feb 05 '23 16:02

chrise


2 Answers

Normally, class A would be an interface class, which both B and C would inherit and implement. But it sounds like you cannot do this for whatever reason.

Since you want to emulate this, you can start by making the interface:

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

And then you make a template wrapper:

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;
};

This essentially does half of what your own example class A was trying to do, but now you can use a common interface. All you need to do is construct the correct templated version you want:

std::shared_ptr<A_interface> a;

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

a->doStuff();
like image 102
paddy Avatar answered Feb 08 '23 17:02

paddy


You need to have both members implement a common interface to use them similarly. But in order to do that, you need to define the interface and relay the calls to the B and C classes.

// 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
}

But typing this up made me realize that defining D and E could get really tiresome and against what you're trying to save. However, you can define a template to create them like @paddy has done.

like image 34
kmdreko Avatar answered Feb 08 '23 15:02

kmdreko