DanielPanuco
DanielPanuco

Reputation: 9

How to operate on only one type of derived class when working with multiple derived classes?

I have 1 base class, Item, and 3 derived classes: CD, Book, & List.

I figured out how to print out and add Item objects, regardless of whether it's a Book or CD, in a vector within a List object. But I can't figure out how to print only Books or only CDs. I can't make any mentions of a CD or Book class in the List class, and I can't move the bool isBook or isCD members to the base class.

class Item
{
protected:
   string name; 
   int id; 

public: 
    //pure virtual methods (ex: virtual bool isID(int); 
};

class CD: public Item
{
private:
    bool isCD; 

public: 
    //defining virtual methods from base class for class specific operations
    virtual string format() { return "Artist: "  + name } 
};

class Book: public Item
{
private:
    bool isBook; 

public: 
    //defining virtual methods from base class for class specific operations
    virtual string format() { return "Author: "  + name } 
};

class List: public Item
{
private:
    vector<Item*> holdings; 

public: 
    void Add(Item &adding) {} // already figured out  

    void printAll() // print all objects in vector regardless of type Book or CD
    {
        for(auto &i: holdings)
            cout << i->format() << '\n'; 
    } 

    void printBooks(){} 
    void PrintCDs(){}
}

Upvotes: 0

Views: 49

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597051

You don't need the isCD and isBook boolean members in each class. You can use dynamic_cast instead, eg:

class List: public Item
{
private:
    vector<Item*> holdings; 

public: 
    ...

    void printAll() const
    {
        for(auto *i: holdings)
            cout << i->format() << '\n'; 
    } 

    void printBooks() const
    {
        for(auto *i: holdings)
        {
            if (Book *b = dynamic_cast<Book*>(i))
                cout << b->format() << '\n'; 
        }
    } 

    void PrintCDs() const
    {
        for(auto *i: holdings)
        {
            if (CD *c = dynamic_cast<CD*>(i))
                cout << c->format() << '\n'; 
        }
    } 
};

If you don't want to use this approach, then you can use some additional virtual methods instead, eg:

class Item
{
    ...
public: 
    ...
    virtual bool isBook() const { return false; }
    virtual bool isCD() const { return false; }
};

class CD: public Item
{
    ...
public: 
    ...
    bool isCD() const override { return true; }
};

class Book: public Item
{
    ...
public: 
    ...
    bool isBook() const override { return true; }
};

class List: public Item
{
private:
    vector<Item*> holdings; 

public: 
    ...

    void printAll() const
    {
        for(auto *i: holdings)
            cout << i->format() << '\n'; 
    } 

    void printBooks() const
    {
        for(auto *i: holdings)
        {
            if (i->isBook())
                cout << i->format() << '\n';
        }
    } 

    void PrintCDs() const
    {
        for(auto *i: holdings)
        {
            if (i->isCD())
                cout << i->format() << '\n';
        }
    } 
};

Alternatively:

enum ItemType { itCD, itBook };

class Item
{
    ...
public: 
    ...
    virtual ItemType getType() const = 0;
};

class CD: public Item
{
    ...
public: 
    ...
    ItemType getType() const override { return itCD; }
};

class Book: public Item
{
    ...
public: 
    ...
    ItemType getType() const override { return itBook; }
};

class List: public Item
{
private:
    vector<Item*> holdings; 

public: 
    ...

    void printAll() const
    {
        for(auto *i: holdings)
            cout << i->format() << '\n'; 
    } 

    void printBooks() const
    {
        for(auto *i: holdings)
        {
            if (i->getType() == itBook)
                cout << i->format() << '\n';
        }
    } 

    void PrintCDs() const
    {
        for(auto *i: holdings)
        {
            if (i->getType() == itCD)
                cout << i->format() << '\n';
        }
    } 
};

Upvotes: 1

Related Questions