GAVD
GAVD

Reputation: 2134

Distinc derived class C++

I have a base class and two derived classes. Now I want to create a vector of base class. When I add new element, it checks which class of the new element. But in C++, there is no function like instanceOf, so I must add variable type to check. Here my piece of code.

class Element {
public:
    int type;
    int getIndex() const {
        return index;
    }

    void setIndex(int index) {
        this->index = index;
    }

    const std::string& getMsg() const {
        return msg;
    }

    void setMsg(const std::string& msg) {
        this->msg = msg;
    }

    std::string toString() {
        std::stringstream sbuf;
        sbuf << "index: " << index << "\n";
        sbuf << "Message: " << msg << "\n";
        return sbuf.str();
    }

private:
    int index;

    std::string msg;

};

Two derived class:

class This: public Element {
public:
    This():Element(1){}
    ~This();

    const std::vector<std::string>& getArguments() const {
        return arguments;
    }

    void setArguments(const std::vector<std::string>& arguments) {
        this->arguments = arguments;
    }

    void add(std::string value) {
        arguments.push_back(value);
    }

private:
    std::vector<std::string> arguments;


};

class That: public Element {
public:
    That():Element(2){}
    ~That();

    const std::string& getThatVal() const {
        return thatVal;
    }

    void setThatVal(const std::string& thatVal) {
        this->thatVal = thatVal;
    }

private:
    std::string thatVal;


};

In another class, I want to create the array of Element.

class Visitor {
private:
    int numOfThis = 0;
    int numOfThat = 0;
    std::vector<Element> vecEle;

public:
    void add(Element ele) {
        vecEle.push_back(ele);
        if (ele.type == 1) {
            numOfThis++;
        } else if (ele.type == 2) {
            numOfThat++;
        }
    }

    int getNumOfThat() const {
        return numOfThat;
    }

    int getNumOfThis() const {
        return numOfThis;
    }
};

My question is how to handle this better? is there a design pattern for this situation? Thanks

Upvotes: 0

Views: 76

Answers (2)

Calin
Calin

Reputation: 11

Class Element should be a base class containing a pure virtual function called i.e. VisitElement( Visitor* visitor).

The class Visitor has nothing to do with the class that you described in your code and it is actually implemented as the design pattern called Visitor. This means it contains overloaded functions

void Visit(This* thisElem) {thisElem->VisitElement(this)}

and

void Visit(That* thatElem){thatElem->VisitElement(this)}

This Visitor class also will contain int counterThis and int counterThat. In class This the implementation for VisitElement is as simple as

VisitElement( Visitor* visitor){ visitor->counterThis++;}

In class That the implementation for VisitElemnt is as simple as

VisitElement (Visitor* visitor){ visitor->counterThat++;}

And finally in order to actually count you need to loop over your vector of base class Element pointers and on each pointer contained in the vector call visitor->Visit(elemFromBector). Once the loop is finished you can query the visitor object for the two ints that you need. Keep in mind that this solution involves polymorphism and visitor design pattern and some encapsulation principles that you seem to have missed in your original code .

Don't use dynamic_cast it is inneficient and it should not be in any production code. If you think that you need dynamic_cast think again because something is wrong with your code. Best advice read about polymorphism, encapsulation and visitor design pattern and you should be able to understand my logic very easily.

Upvotes: 1

zhm
zhm

Reputation: 3641

You can store pointers rather than objects in your vector, as:

std::vector<Element *> vecEle;

Then you can use dynamic_cast to determine which derived class is the type of your pointer.

// dynamic_cast will try to convert pointer of base class to derived class, 
// and return NULL on fail
Element *pElem= vecEle[0]; // you can traverse your vector if needed
if (This *pThis = dynamic_cast<This *>(pElem)) {
    // object is This type
} else if (That *pThat = dynamic_cast<That *>(pElem)) {
    // object is That type
}

Upvotes: 4

Related Questions