There is an interesting design problem in your do_something() function: you think that the device type matches the mode parameter, but you cannot check it.
Alternative 1: using dynamic casting
First of all, since you expect your device class to be polymorphic, you must provide a virtual destructor. This ensures that the device is also polymorphic.
Then you can use dynamic casting to make your code reliable (here I assumed that mdode 3 is for I / O, but this is just for a general idea):
void do_something(device* dev, int mode_flag) { if(mode_flag == 1 || mode_flag==3) // just an example { inputDevice* id=dynamic_cast<inputDevice*>(dev); // NULL if it not an input device if (id) { input* in = id->getInput(); // doing strange things with pointers } else cout << "Invalid input mode for device"<<endl; } if(mode_flag == 2 || mode_flag==3) { outputDevice* od=dynamic_cast<outputDevice*>(dev); if (od) { output* out = od->getOutput(); } else cout << "Invalid output mode for device"<<endl; } // ... }
Alternative 2: make do_something method
I donβt know how complicated it is, but if you intend to do something using any devices, you can simply make it a method.
class device { public: virtual void do_something(int mode_flag) = 0; virtual ~device() {} };
You will get an idea. Of course, you can also have a mix that has a global do_something() function that performs common actions and calls member functions for the part, which should depend on the type of device.
Other comments
Note that your inputoutputDevice inherits twice from the device. Once you have members in the device, this can lead to ambiguity. Therefore, I suggest you consider virtual inheritance for a device class.
class inputDevice : public virtual device ...; class outputDevice : public virtual device ...;
Another approach might be to have a more complex I / O interface in the device:
class device { public: virtual bool can_input() = 0;