C ++ class testing for functions

I have a set of classes that describe a set of logical blocks that can store things and do something with them. I have

struct IBox // all boxes do these
{
    ....
}

struct IBoxCanDoX // the power to do X
{
    void x();
}

struct IBoxCanDoY // the power to do Y
{
    void y();
}

Interestingly, what is the “best” or perhaps just “favorite” idiom for the client of these classes to solve these additional features.

and)

    if(typeid(box) == typeid(IBoxCanDoX))
    {
         IBoxCanDoX *ix = static_cast<IBoxCanDoX*>(box);
         ix->x();
    }

b)

   IBoxCanDoX *ix = dynamic_cast<IBoxCanDoX*>(box);
    if(ix)
    {
         ix->x();
    }

c)

if(box->canDoX())
{
    IBoxCanDoX *ix = static_cast<IBoxCanDoX*>(box);
    ix->x(); 
}

d) different class structure now

struct IBox
{
    void x();
    void y();
}
...
box->x(); /// ignored by implementations that dont do x

e) except

box->x() // 'not implemented' exception thrown

f) explicit test function

if(box->canDoX())
{
   box->x();
} 

I am sure there are others.

EDIT:

Just to empty the drawer to use

I expose this material to end users through an interactive ui. They can type "make box do X". I need to know if field x can. Or do I need to disable the command 'make current box do X'

EDIT2: thanks to all responders

(a), ( !). (b)

   template<class T>
    T* GetCurrentBox()
    {
       if (!current_box)
          throw "current box not set";
       T* ret = dynamic_cast<T*>(current_box);
       if(!ret)
          throw "current box doesnt support requested operation";
       return ret;
    }
    ...
    IBoxCanDoX *ix = GetCurrentBox<IBoxCanDoX>();
    ix->x();

UI- ( ).

0
8

"I" "", Java, ++, ... , .

"d", . , , . , Vehicle (), . pedal(), , .

"e" , "d" PLUS, . , (), , , , . 'f' - .

'c' . , , , ICanDoX , , x X().

, 'b' . , , , .

: , 'c' static_cast, . , dynamic_cast , . , .

2: , "a" , , . , typeid , , . , : factory , . - , // . .

+1

, ++:

class IVisitor
{
public:
    virtual void Visit(IBoxCanDoX *pBox) = 0;
    virtual void Visit(IBoxCanDoY *pBox) = 0;
    virtual void Visit(IBox* pBox) = 0;
};

class IBox // all boxes do these
{
public:
    virtual void Accept(IVisitor *pVisitor)
    {
        pVisitor->Visit(this);
    }
};

class BoxCanDoY : public IBox
{
public:
    virtual void Accept(IVisitor *pVisitor)
    {
        pVisitor->Visit(this);
    }
};
class TestVisitor : public IVisitor
{
public:
    // override visit methods to do tests for each type.
};

void Main()
{
    BoxCanDoY y;
    TestVisitor v;
    y.Accept(&v);
}
+4

, , , b d "". , , , ++.

+2

A B (RTTI) , . "canDoX", , , , , , .

X Y, , IBox, .

class IBox{
   virtual void doThing();
}
class IBoxCanDoX: public IBox{
   void doThing() {  doX(); }
   void doX();
}
class IBoxCanDoY: public IBox{
   void doThing() {  doY(); }
   void doY();
}

box->doThing();

, . , , /// ( ).

+1

- , , , .

template<class box>
void box_do_xory(box BOX){
    BOX.xory();
}
0

. . :
- a), b)


- b) , , , dynamic_cast
- c) b), ( dynamic_cast)
- e) , , ,
- d) , f) ( )
- d) e) f) , ,

0

, .

, , , , , . , . , ( ), , , . X() {Y} X, , , Y, . X , , ( std::vector ).

, , , .

0

, , . SFINAE . "++ Template Metaprogramming". doIt x, , y. CanDo, . , , doIt .

#include <iostream>
#include <boost/config.hpp>
#include <boost/utility/enable_if.hpp>

typedef char yes;      // sizeof(yes) == 1
typedef char (&no)[2]; // sizeof(no)  == 2

template<typename T>
struct CanDo {
    template<typename U, void (U::*)()>
    struct ptr_to_mem {};

    template<typename U>
    static yes testX(ptr_to_mem<U, &U::x>*);

    template<typename U>
    static no testX(...);

    BOOST_STATIC_CONSTANT(bool, value = sizeof(testX<T>(0)) == sizeof(yes));
};

struct DoX {
    void x() { std::cout << "doing x...\n"; }
};

struct DoAnotherX {
    void x() { std::cout << "doing another x...\n"; }
};

struct DoY {
    void y() { std::cout << "doing y...\n"; }
};

struct DoAnotherY {
    void y() { std::cout << "doing another y...\n"; }
};

template <typename Action>
typename boost::enable_if<CanDo<Action> >::type
doIt(Action* a) {
    a->x();
}

template <typename Action>
typename boost::disable_if<CanDo<Action> >::type
doIt(Action* a) {
    a->y();
}

int main() {

    DoX         doX;
    DoAnotherX  doAnotherX;
    DoY         doY;
    DoAnotherY  doAnotherY;

    doIt(&doX);
    doIt(&doAnotherX);
    doIt(&doY);
    doIt(&doAnotherY);
}
0

Source: https://habr.com/ru/post/1769616/


All Articles