Oliver
Oliver

Reputation: 928

C++ Multiple Condition Statements - Merging

I have written a program according to a specification.
The Specification has about 3 types and each type gets handled differently on every single point.

That means more or less for code readability, I have written it like shown below, now my question is, if you have 200 such statements, wouldn't it be worth to merge them all into one "if enum-type x"

I would believe there is a program out there which already does it but google didn't help me much for this specific problem. Thanks for help in advance.

/* Point 1.15 Filling Customers bdate */

if(current.identifier == APPLE){ output.setValue(1.15, additionalObj.some.color)}
if(current.identifier == PLUM){ output.setValue(1.15, otherObj.another.color) }
if(current.identifier == GRAPE){ output.setValue(1.15, default::color) }


/* Point 1.16 Filling Customers cash*/

if(current.identifier == APPLE){ do whatever}
if(current.identifier == PLUM){ do whatever}
if(current.identifier == GRAPE){ do whatever}

Result to be achieved:

if(current.identifier == APPLE){ output.setValue(1.15, additionalObj.some.color) 
                                 do whatever
}

And so on so i can merge them into 1 statement automatically while i still have the readable code

Edit: I might have misinformed you, its actually not a type its just an Object with a String identifier and SubObjects so i can't use polymorphism. I have adjusted the above so you can see what i would like to achieve.

Upvotes: 1

Views: 461

Answers (4)

ksming
ksming

Reputation: 1462

Read about C++ class inheritance and polymorphism if you have not understood them already. These two features of C++ will provide a more elegant way to solve your problem.

Upvotes: 5

Ken Wayne VanderLinde
Ken Wayne VanderLinde

Reputation: 19349

There's two ways I would to do this: the first is by polymorphic behaviour (either via virtual functions, or type parameterization); the second would be to switch on the type.

For the first one, each of the type can inherit from a common (possibly abstract) base class:

class Base
{
public:

    virtual void DoSomething( ) =0;

};

class A : public Base
{
public:
    void DoSomething( )
    {
        cout << "I'm doing something from A!" << endl;
    }
};

class B : public Base
{
public:
    void DoSomething( )
    {
        cout << "I'm doing something from B!" << endl;
    }
};

This way, you can simply use a variable of type Base &, Base *, or any smart pointer of Base (e.g. shared_ptr<Base), and call the DoSomething method on that variable. The correct implementation of DoSomething would be called based on the run-time type of the variable (since DoSomething is a virtual method).

Another way to acheive similar behaviour is via templates. It's used in a similar way as the first suggestion, but you don't need a base class, and the methods need not be virtual:

class A
{
public:
    void DoSomething( )
    {
        cout << "I'm doing something from A!" << endl;
    }
};

class B
{
public:
    void DoSomething( )
    {
        cout << "I'm doing something from B!" << endl;
    }
};

Then the function which handles the operations can be defined something like this:

template<typename T>
void PolymorphicDoSomething( T variable )
{
    T.DoSomething( );
}

and used like this:

A a;
PolymorphicDoSomething( a );

Of course, this example is a little contrived, but that's the fundamental idea, and can be very useful depending on the situation.

The other possibility would be to essentially do what you're doing now, but with a single switch statement, rather than several if statements. If the type of the variable is stored as an enum or an int, you can use a switch to efficiently determine which operations to perform:

enum VariableType
{
    TypeA,
    TypeB,
    TypeC,
    // etc.
};

//...

switch(variable_type)
{
case TypeA:
    DoSomethingForA( );
    break;
case TypeB:
    DoSomethingForB( );
    break;
case TypeC:
    DoSomethingForC( );
    break;
// etc.
}

But I doubt that this would really be any more effective than using virtual methods. Also, virtual methods are more managable - in order to extend the functionality, you must simply declare another class, and all the code you already have will be able to cope with it. In the case of a switch, you would have to add a case statement everywhere you check the variable's type. So I would really stick with virtual methods in this case.

Upvotes: 1

Keith
Keith

Reputation: 6834

Basic polymorphic approach:

enum Type { tX, tY, tZ};

struct Data
{
    Type type;
    int data_;
};

class Processor
{

public:

    virtual void fillCustomersBDate(const Data& data) = 0; 
    virtual void fillCustomersCash(const Data& data) = 0;

};

class XProcessor : public Processor 
{
    virtual void fillCustomersBDate(const Data& data) { /* X stuff */}
    virtual void fillCustomersCash(const Data& data) {/* X stuff */}
};
class YProcessor : public Processor 
{
    virtual void fillCustomersBDate(const Data& data) {/* Y stuff */}
    virtual void fillCustomersCash(const Data& data) {/* Y stuff */}
};

void process(const Data& data)
{
    Processor* processor = processorForType(data.type);
    // Do general stuff
    processor->fillCustomersBDate(data);
    // Do general stuff
    processor->fillCustomersCash(data);
    // Do general stuff
    delete processor;
}

More likely, you'd move most of the main flow into the base class.

Upvotes: 3

paxdiablo
paxdiablo

Reputation: 881783

If they're all distinct, you can separate them into individual sections like:

if (type x)
    processX1v1_thru_1v15(); // will do all steps 1.1 thru 1.16 for type x
else if (type y)
    processY1v1_thru_1v15(); // will do all steps 1.1 thru 1.16 for type y
: : :
and so on.

But you may want to look into polymorphism which will allow you to specify a different "whatever" for each class/type. The you can just do domething like:

obj.doWhatever1_01();  // calls obj-specific method depending on type.
obj.doWhatever1_02();
: : :
obj.doWhatever1_16();

Upvotes: 0

Related Questions