Inheritance of a hierarchy versus multiple inheritance (C ++)

Well, I’ve been thinking about a design solution for the past few days, and since I still can’t support each other, I thought maybe someone has an idea.

The situation is this: I have a couple of different classes of interface abstracting several communication devices. Since these devices differ in nature, they also differ in interface and, therefore, are not connected to each other. Let's call them IFooDevice and IBarDevice . Over time, additional types of devices may be added. Language - C ++.

Since other components (called clients from now on) can use one or more of these devices, I decided to provide a DeviceManager class to handle access to all available devices at runtime. Since the number of types of devices can increase, I would like to treat all devices equally (from the point of view of managers). However, clients will request a specific type of device (or device based on some properties).

I thought of two possible solutions:

The first will be some kind of hierarchy of intervention. All devices will subclass the common IDevice interface , which will provide the (virtual) methods needed to manage and query the device (e.g. getProperties (), hasProperties (), ...). DeviceManager has a collection of pointers to an IDevice , and at some point a throw from Base to Derived will be required - either using the template method in the manager, or after a request on the client side.

, , . , : IManagedDevice , , IFooDevice. , "" . IManagedDevice. - (, IManagedDevice IFooDevice), , .

? ? - ?

Edit:

"" . , , , () . , . "" , , . , , ( , ), . , , .

+5
5

, .

+1

, :

class IManagedDevice
{
    IDevice* myDevice;

    /* Functions for managing devices... */
};

IDevice , . , .

(IFooDevice IBarDevice), , .

, , , - :

class IDevice
{
    virtual void Handle() = 0;
};

class IFooDevice : public IDevice
{
    virtual void Handle()
    {
        this->doFoo();
    }

    virtual void doFoo() = 0;
}

class IBarDevice : public IDevice
{
    virtual void Handle()
    {
        this->doBar();
    }

    virtual void doBar() = 0;
}

Handle.

+1

, , , . - :

struct Device
{
    static Device *first;  // Pointer to first available device
    Device *prev, *next;   // Links for the doubly-linked list of devices

    Device() : prev(0), next(first)
    {
        if (next) next->prev = this;
        first = this;
    }

    virtual ~Device()
    {
        if (next) next->prev = prev;
        if (prev) prev->next = next; else first = next;
    }

    private:
        // Taboo - the following are not implemented
        Device(const Device&);
        Device& operator=(const Device&);
 };

Device, .

, Device::first device->next. dynamic_cast<NeededDeviceType*>(device) , , .

, , (, , ..), Device.

+1

.

, Boost.Asio. -

/** An interface to basic communication with a decive.*/
class coms_manager
{
public:
  virtual 
  ~coms_manager();
  /** Send a command. */
  virtual 
  void 
  send(const std::string& cmd) = 0;

  /** Receive a command.
   *  @param buffsize The number of bytes to receive.
   *  @param size_exactly True if exactly buffsize bytes are to be received.  If false, then fewer bytes may be received.
   */
  virtual 
  std::string 
  recv( const unsigned long& buffsize = 128, 
    const bool& size_exactly = false) = 0 ;

  /** Timed receive command.
   *  @param buffsize The number of bytes to receive.
   *  @param seconds The number of seconds in the timeout.
   *  @param size_exactly True if exactly buffsize bytes are to be received.  If false, then fewer bytes may be received.
   */
  virtual 
  std::string 
  timed_recv( const unsigned long& buffsize = 128, 
      const double& seconds = 5, 
      const bool& size_exactly = false) = 0;
};

tcp (ethernet) .

class serial_manager : public coms_manager {};
class ethernet_manager : public coms_manager {};

( ) ( ) coms_manager :

class Oscilloscope
{
  void send(const std::string& cmd)
  {  
     m_ComsPtr->send(cmd);
  }
private:
  coms_manager* m_ComsPtr;
};

, , .

( ethernet,

template<class Manager>
class Oscilloscope
{
  void send(const std::string& cmd)
  {  
     m_Coms.send(cmd);
  }
private:
  Manager m_Coms;
};

Oscilloscope<serial_manager> O1(/dev/tty1);   // the serial port
Oscilloscope<ethernet_manager> O2(10.0.0.10); //The ip address

.

. , - , , .

0

, , . (, ,...) , .

However, if you need to separate the interface between management and device functionality, you can use virtual inheritance . IManagedDevice and IFooDevice are interfaces of the same specific device, therefore both of them have the general virtual basic IDevice.

Specifically (startup code) :

#include <cassert>

class IDevice {
public:
  // must be polymorphic, a virtual destructor is a good idea
  virtual ~IDevice() {}
};

class IManagedDevice : public virtual IDevice {
    // management stuff
};

class IFooDevice : public virtual IDevice {
    // foo stuff
};

class ConcreteDevice : public IFooDevice, public IManagedDevice {
    // implementation stuff
};

int main() {
    ConcreteDevice device;
    IManagedDevice* managed_device = &device;
    IFooDevice* foo_device = dynamic_cast<IFooDevice*>(managed_device);
    assert(foo_device);
    return 0;
}
0
source

All Articles