1

in my program I have 2 headers (IP and MAC headers) that are 'sons' of GeneralHeader. All General, IP and MAC headers classes have PrintMe() function. In addition, I have a Packet class that holds list of GeneralHeaders (the list actually may have IP or MAC headers: (without IP defenition, to shorten):

//Packet.h

    class GeneralHeader {
    public:
        bool Valid;
        HeaderType_t HeaderType; // MAC or IP
        virtual void PrintMe();
    };

    class HW_MACHeader: public GeneralHeader {
    public:
        long unsigned DestAddr:48;
        long unsigned SourceAddr:48;
        virtual void PrintMe();
    };

    struct NetworkPacket_t {
        NetworkPacket_t();
        list<GeneralHeader> Headers;//TODO GeneralHeader
        void PrintMe();
    };

I have dificulty to implement the PrintMe() method that will print the list of GeneralHeaders using the appropriate for MAC or IP PrintMe() method (not the base PrintMe() of GeneralHeader):

//Packet.cpp

//This implementation prints GeneralHeaders :(
//(although MAC headers were added to the Headers list)

void NetworkPacket_t::PrintMe() {
    list<GeneralHeader>::iterator it_H;
    for (it_H = Headers.begin(); it_H != Headers.end(); ++it_H) {
        it_H->PrintMe();
    };
};

Another try was to cast the iterator it_H to appropriate MAC or IP header (according to HeaderType), but whichever way i tried to cast it, it did not work, e.g.:

//Packet.cpp
//Casting implementation
//Here I get run error: 
//terminate called after throwing an instance of 'std::bad_cast'

void NetworkPacket_t::PrintMe() {
    list<GeneralHeader>::iterator it_H;
    for (it_H = Headers.begin(); it_H != Headers.end(); ++it_H) {
        switch (it_H->HeaderType) {
        case General_Header_type:
            std::cout << " General Header " << endl;
            it_H->PrintMe();
            break;
        case MAC_Header_type:
            dynamic_cast<HW_MACHeader&>(*it_H).PrintMe();
            break;
        default:
            std::cout << " default" << endl;
        };
    };
};

I really appreciate any help you can prvide

Halona
  • 1,475
  • 1
  • 15
  • 26
  • You can't store derived objects in a collection that stores the base object. Read about [object slicing](http://en.wikipedia.org/wiki/Object_slicing). – Some programmer dude Mar 12 '14 at 09:33

2 Answers2

1

The reason is that you stored the object rather than its pointer into the list. It's something like:

HW_MACHeader hw;
GeneralHeader gh = hw;

You assign the child object to parent object, so the gh in the example is actually the first part of the hw. You could read about the object slicing.

Using pointer is the right way:

HW_MACHeader hw;
GeneralHeader *gh = &hw;

Then when you call

gh->PrintMe();

It will call the PrintMe function in HW_MACHeader.

Take a look at this:

#include <iostream>
#include <list>
using namespace std;

class GeneralHeader {
public:
    bool Valid;
    virtual void PrintMe() {cout << "General" << endl;}
};

class HW_MACHeader: public GeneralHeader {
public:
    long unsigned DestAddr;
    long unsigned SourceAddr;
    virtual void PrintMe() {cout << "HW" << endl;}
};

struct NetworkPacket_t {
    NetworkPacket_t(){}
    list<GeneralHeader *> Headers;//TODO GeneralHeader
    virtual void PrintMe();
};

void NetworkPacket_t::PrintMe() {
    list<GeneralHeader *>::iterator it_H;
    for (it_H = Headers.begin(); it_H != Headers.end(); ++it_H) {
        (*it_H)->PrintMe();
    }
}

int main()
{
    NetworkPacket_t t;
    HW_MACHeader t1;
    GeneralHeader t2;
    t.Headers.push_back(&t1);
    t.Headers.push_back(&t2);

    t.PrintMe();
    return 0;
}

All the assignments are replaced to pointer rather than object. The output is:

HW
General
Community
  • 1
  • 1
feihu
  • 1,935
  • 16
  • 24
0

You can store smart pointers in the container,

list<shared_ptr<GeneralHeader>>

then virtual functions will work as intended through the pointer to the base class.

Spock77
  • 3,256
  • 2
  • 30
  • 39