Inheritance hierarchy vs. multiple inheritance (C++) - c++

Well, I was thinking about a design decision for the past few days and since I still cannot favor one over the other I thought maybe someone else has an idea.
The situation is the following: I have a couple of different interface classes abstracting several communication devices. Since those devices differ in their nature they also differ in the interface and thus are not really related. Lets call them IFooDevice and IBarDevice. More device types may be added over time. The language is C++.
Since other components (called clients from now on) might want to use one or more of those devices, I decided to provide a DeviceManager class to handle access to all available devices at runtime. Since the number of device types might increase, I would like to treat all devices equally (from the managers point of view). However, clients will request a certain device type (or devices based on some properties).
I thought of two possible solutions:
The first would be some kind of interitance hierarchy. All devices would subclass a common interface IDevice which would provide the (virtual) methods necessary for management and device query (like getProperties(), hasProperties(), ...). The DeviceManager then has a collection of pointers to IDevice and at some point a cast from Base to Derived would be necessary - either with a template method in the manager or after the request on the client's side.
From a design point of view, I think it would be more elegant to seperate the concerns of managing a device and the interface of the specific device itself. Thus it would lead to two unrelated interfaces: IManagedDevice and e.g. IFooDevice. A real device would need to inherit from both in order to "be" of a specific device type and to be managaeble. The manager would only manage pointers to IManagedDevice. However, at some point there will be the need to cast between now unrelated classes (e.g. from IManagedDevice to IFooDevice) if a client wants to use a device provided by the manager.
Do I have to choose the lesser of two evils here? And if so which one would it be? Or do I miss something?
Edit:
About the "managing" part. The idea is to have library providing a variety of communication devices different (client) applications can use and share. Managing merely comes down to the storage of instances, methods for registering a new device and looking up a certain device. The responsibility for choosing the "right" device for the task is up to the client side because it knows best which requirements it puts on the communication. In order to reuse and thus share available devices (and by that I mean real instances and not just classes) I need a central access point to all available devices. I'm not too fond of the manager itself but it's the only thing I could come up to in that case.

I think the visitor pattern is a better choice for this.

I think what Tom suggested might be altered a bit to suit your needs:
class IManagedDevice
{
IDevice* myDevice;
/* Functions for managing devices... */
};
In this case IDevice is an empty interface that all devices inherit from. It gives no real benefit, just make the class hierarchy handling slightly more bearable.
Then, you can have then ask for the specific device (IFooDevice or IBarDevice), probably via some sort of device type ID.
If all you need is to have a common code to manage the devices, and then pass each device to the appropriate place I think you can get away with something like this:
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;
}
With the manager calling the Handle function.

I think I'd go for a simple solution of having a base class for Device that takes care of registering the device in the global device list and then static methods for looking them up. Something like:
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&);
};
Then you can just derive all devices from Device and them will be automatically placed in the global list on construction and removed from the global list on destruction.
All your clients will be able to visit the list of all devices by starting from Device::first and following device->next. By doing a dynamic_cast<NeededDeviceType*>(device) clients can check if the device is compatible with what they need.
Of course any method that is implemented in every device type (e.g. a description string, a locking method to ensure exclusive use by one client and the like) can be exported also at the Device level.

when communicating with devices I separated the the device and the communication manager completely.
I had a simple communication manager that was based on Boost.Asio. The interface was something like
/** 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;
};
I then implemented this interface for tcp (ethernet) and serial communications.
class serial_manager : public coms_manager {};
class ethernet_manager : public coms_manager {};
Each of the devices then contained (or pointed to) (rather than inherited) a coms_manager object
For example:
class Oscilloscope
{
void send(const std::string& cmd)
{
m_ComsPtr->send(cmd);
}
private:
coms_manager* m_ComsPtr;
};
You can then swap around the communication method by changing what the pointer points to.
For me, this didn't make much sense (the Oscilloscope was EITHER attached via serial OR via ethernet and so I actually opted for
template<class Manager>
class Oscilloscope
{
void send(const std::string& cmd)
{
m_Coms.send(cmd);
}
private:
Manager m_Coms;
};
and I now use
Oscilloscope<serial_manager> O1(/dev/tty1); // the serial port
Oscilloscope<ethernet_manager> O2(10.0.0.10); //The ip address
which makes more sense.
As for your suggestion as to have a generic device interface. I started with that too, but then wasn't sure of its utility - I always wanted to know exactly what equipment I was sending a command to, I neither needed nor wanted to work through an abstract interface.

At a first glance, the first approach seems fine for me if all devices need to be managed and no other stuff can be done with an unknown device. The meta data for a general device (e.g. name, ...) would typically be the data one need for managing devices.
However, if you need to separate the interface between the management and the device functionality, you can use virtual inheritance.
IManagedDevice and IFooDevice are both interfaces of the same concrete device, so they both have a common virtual base IDevice.
Concretely (run 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;
}

Related

Designing class for handling multiple communication protocols handling

I am developing a C++ application which should handle multiple communication protocols (Ethernet, Serial, etc.). Each of the communication protocols is handled as a specific class.
In order to expose as little as possible information about the internal structure and organization of the said classes and protocols, I would like to somehow wrap all of this functionality and provide somewhat generic API for sending data over a selected protocol.
Basically, what API should provide (the parameters are not restricted to this, but is the general idea):
bool sendData(uint8_t* buffer, const size_t& bufferSize);
void receiveData(uint8_t* dataBuffer, size_t& bufferSize);
What is the best way to create a generic API for the said functionality, and if possible involve some design pattern?
Regards.
What is the best way to create a generic API for the said
functionality, and if possible involve some design pattern?
The Strategy Pattern looks suitable in this scenario.
First, define an interface for all your distinct communication startegies, Communication:
class Communication {
public:
virtual ~CommunicationStrategy() = default;
virtual bool sendData(uint8_t* buffer, const size_t& bufferSize) = 0;
virtual void receiveData(uint8_t* dataBuffer, size_t& bufferSize) = 0;
};
Then, your concrete implementations – i.e., strategies – should derive from this interface:
class EthernetCommunication: public Communication {
public:
// ...
bool sendData(uint8_t*, const size_t&) override;
void receiveData(uint8_t*, size_t&) override;
};
class SerialCommunication: public Communication {
public:
// ...
bool sendData(uint8_t*, const size_t&) override;
void receiveData(uint8_t*, size_t&) override;
};
class CarrierPigeon: public Communication {
public:
// ...
bool sendData(uint8_t*, const size_t&) override;
void receiveData(uint8_t*, size_t&) override;
};
The client code will work with a (pointer to) Communication – i.e., the interface – rather than directly with a particular implementation like EthernetCommunication, SerialCommunication, or CarrierPigeon. Thus, the code follows the "program to an interface, not to an implementation" advice. For example, you may have a factory function like:
std::unique_ptr<Communication> CreateCommunication();
This factory function returns one of the strategies above. Which strategy to return can be determined at run time.
std::unique_ptr<Communication> com = CreateCommunication();
// send data regardless of a particular communication strategy
com->sendData(buffer, bufferSize);
This way, the code above isn't coupled to any particular implementation, but only to the interface Communication which is common to all the different possible communication strategies.
If the different communication strategies don't need per-instance data, just having two callbacks instead of an object will do:
using data_sender_t = bool (*)(uint8_t*, const size_t&);
using data_receiver_t = void (*)(uint8_t*, size_t&);
// set these function pointers to the strategy to use
data_sender_t data_sender;
data_receiver_t data_receiver;

Alternative to Inner Classes in C++

Let's say I am writing a "Device Tree Blob" for the bcm2835 RPi chip but in C++ files, rather then .dts files. The intent is to practice C++ and OS concepts.
I would like to be able to encapsulate not just register addresses, but functions which access those, and expose only top level uses as API functions.
In C++ this could be inner classes, to one big BCM2835 class like so:
//bcm2835.h
class BMC2835 : public ARMCpu
{
public:
void ACKLedOn(void);
void ACKLdOff(void);
void ACKLedBlink(void);
// I2C write to device (this would be called by the device driver)
// It would ensure that I2C is setup, etc, etc
void I2C_Device_Write(I2C_Device* device, uint8_t* buffer);
private:
// Physical addresses for various peripheral register sets
/// Base Physical Address of the BCM 2835 peripheral registers
const uint32_t BCM2835_PERI_BASE = 0x20000000;
class GPIO()
{
private:
/// Base Physical Address of the Pads registers
const uint32_t BCM2835_GPIO_PADS = (BCM2835_PERI_BASE + 0x100000)
/// Sets the Function Select register for the given pin, which configures
/// the pin as Input, Output or one of the 6 alternate functions.
void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode);
}
class I2C()
{
private:
const uint32_t BCM2835_CORE_CLK_HZ = 250000000 ;///< 250 MHz
// Register masks for BSC_C
const uint32_t BCM2835_BSC_C_I2CEN = 0x00008000;///< I2C Enable, 0 = disabled, 1 = enabled
const uint32_t BCM2835_BSC_C_INTR = 0x00000400;///< Interrupt on RX
const uint32_t BCM2835_BSC_C_INTT = 0x00000200;///< Interrupt on TX
void bcm2835_i2c_begin(void);
void bcm2835_i2c_write(uint8_t address, uint8* pbuffer);
}
}
And then I can also have a class for the BCM2837 which is 64-bit and handles the LED very differently for example.
//bcm2837.h
class BCM2837 : public ARMCpu
{
public:
// LED is now a very different Implementation with Mailbox
// but exposed to Kernel as API
void ACKLedOn(void);
void ACKLdOff(void);
void ACKLedBlink(void);
...
...
}
I am sure there many problems with this approach. The one that seems to bother me the most is the length of the single class after you include things like SPI, UART, etc, etc.
Even if the ARMCpu is well desigend and 100% virtual (which I would rather avoid in embedded), each CPU class will still be rather lengthy and difficult to read and maintain.
Is there a way to achieve this type of private level access in C++ which is easier?
Put each chip in its own .cpp file, and declare all those private, internal things within that file (and not in the header). You can wrap them in anonymous namespace to keep them from being exposed to the linker.

Best design pattern for switching between hardware interfaces

I am seeking advice about whether or not my current approach makes sense. If not, I'd like a recommendation about some type of design pattern than can be used to replace my current intuition.
My premise is that I have a camera that requries a frame grabber card with either a CameraLink or CoaXPress cable interface to connect to a PC. All communication and data transfer between the camera and computer must be controlled using the frame grabber card, so the coupling between these two physical hardware objects is very tight.
My problem is that I want to create a "Camera" object (for a GUI) which has-a "FrameGrabber" card object that it uses to acquire data and send/receive commands and data. However, I have many different frame grabber cards of many different types. Lets call them CoaxGrabberA, CoaxGrabberB, LinkGrabberA, and LinkGrabberB. The CoaxGrabbers require a different set of parameters for initialization, setters, and getters than the LinkGrabbers.
As a result, I think I need to use two levels of inheritance, but from everything I've read, inheritance should be used very rarely, and composition should be favored. As such, I am extremely doubting my design decisions, and seek some type of better design. Here's an example of some half-baked code. It's a bit lengthy, but the important part is the concept that CoaxGrabberA, CoaxGrabberB, LinkGrabberA, and LinkGrabberB are grandchildren of FrameGrabber, which must be accessible to Camera. Everything else is to fill in the meat for details you may need.
My goal is to, at runtime, select whichever framegrabber (of any make/model/interface) that I want to use for my Camera object. Furthermore, I want to easily access all of the member functions that are unique to that grandchild framegrabber type to modify the behavior of the hardware at runtime.
My question is "is there a particular design pattern to match my problem that I don't know about, which would make my life easier than using my naive, intuitive approach"
//-----------------------------------------
// Parent Class
//=========================================
class FrameGrabber {
public:
virtual void sendCommandString(std::string cmd) = 0;
virtual void startAcquisition() = 0;
virtual void stopAcquisition() = 0;
};
//-----------------------------------------
// Children Classes
//=========================================
class CoaxGrabber : FrameGrabber {
public:
//functions unique to coax grabbers
virtual void setCommAddress(int commAddress) = 0;
virtual void setStatusPort(int statusPort) = 0;
//functions universal to all grabbers
virtual void sendCommandString(std::string cmd) = 0;
virtual void startAcquisition() = 0;
virtual void stopAcquisition() = 0;
protected:
int _commAddress;
int _statusPort;
};
class LinkGrabber : FrameGrabber {
public:
//functions unique to link grabbers
virtual void setBaudRate(int baudRate) = 0;
virtual void setNumChannels(int numChannels) = 0;
//functions universal to all grabbers
virtual void sendCommandString(std::string cmd) = 0;
virtual void startAcquisition() = 0;
virtual void stopAcquisition() = 0;
protected:
int _baudRate;
int _numChannels;
};
//-----------------------------------------
// Grandchildren Classes
//=========================================
class CoaxGrabberA : public CoaxGrabber {
//identical public members as CoaxGrabber
//different implementation using
//different low-level API, ex: BitFlow
}
class CoaxGrabberB : public CoaxGrabber {
//identical public members as CoaxGrabber
//different implementation using
//different low-level API, ex: Kaya
}
class LinkGrabberA : public LinkGrabber {
//identical public members as LinkGrabber
//different implementation using
//different low-level API, ex: NationalInstruments
}
class LinkGrabberB : public LinkGrabber {
//identical public members as LinkGrabber
//different implementation using
//different low-level API, ex: Imperx
}
//-----------------------------------------------------
// Finally, my Camera object, nothing too interesting here
//=====================================================
class Camera {
public:
Camera() {
_frameGrabber = NULL;
}
~Camera() {
delete _frameGrabber;
}
void setGrabber(FrameGrabber* newGrabber)
{
delete _frameGrabber;
_frameGrabber = newGrabber;
}
void startAcquisition() {
_frameGrabber.startAcquisiton();
}
void stopAcquisition() {
_frameGrabber.stopAcquisition();
}
int setSensitivity(int sens) {
_frameGrabber.sendCommandString("sens=" + std::to_string(sens));
}
private:
FrameGrabber* _frameGrabber;
};
//-----------------------------------------
// This is why I don't like my Camera object
// the actual end-user interface smells
//=========================================
class CameraGui : QMainWindow
{
public:
void setGrabberType(int type);
void setCoaxGrabberCommAddress(int address);
void setLinkGrabberBaudRate(int rate);
CameraSystem _myCamera;
CoaxGrabber* _myCoaxGrabber;
LinkGrabber* _myLinkGrabber;
};
//---------------------------------------------------------------
//This function smells to me, but I cannot think of any other way
//of course, int type will be enum in actual program.
//===============================================================
void CameraGui::setGrabberType(int type) {
switch (type) {
case 0:
delete _myCoaxGrabber;
_myCoaxGrabber = new CoaxGrabberA();
_myCamera.setGrabber(&_myCoaxGrabber);
break;
case 1:
delete _myCoaxGrabber;
_myCoaxGrabber = new CoaxGrabberB();
myCamera.setGrabber(&_myCoaxGrabber));
break;
case 2:
delete _myLinkGrabber;
_myLinkGrabber = new LinkGrabberA();
_myCamera.setGrabber(&_myLinkGrabber);
break;
case 3:
delete _myLinkGrabber;
_myLinkGrabber = new LinkGrabberB();
_myCamera.setGrabber(&_myLinkGrabber);
break;
}
}
//---------------------------------------------------------------
// this method of setting parameters also smells to me,
// since this data is linked to the Camera object, which
// will have no way of knowing whether the state of its
// framegrabber changed... furthermore, if I change framegrabbers,
// none of the parameter settings (state) will be remembered.
// the user will need to set them all over again.
// the only way I know to circumvent this is to allocate memory for
// every type of framegrabber, and broadcast all state changes to
// all applicable parent grabbers, which will reside in permanent
// memory until the application closes.
//===============================================================
void CameraGui::setCoaxGrabberCommAddress(int address) {
if(myCoaxGrabber != NULL) {
myCoaxGrabber->setCommAddress(address);
}
}
//likewise smell
void CameraGui::setLinkGrabberBaudRate(int rate) {
if(myLinkGrabber != NULL) {
myLinkGrabber->setBaudRate(rate);
}
}
Any and all advice will be greatly appreciated. Long story short, I know little about OO design patterns, but this feels like a solved problem and I feel like I'm reinventing the wheel. Is there a better, more established way to implement what I am trying to do?
Your design pattern is called "factory" and there is nothing wrong with inheritance (https://en.wikipedia.org/wiki/Factory_method_pattern)
The rule of thumb what we should use when choose between inheritance and aggregation:
if something reflect "is" relationship (e.g. CoaxGrabber is FrameGrabber) use inheritance.
if something reflect "has" relationship (e.g. CameraGui has FrameGrabber) use aggregation.
I would recommend using smart pointers (e.g. std::shared_ptr) instead of new and delete what is currently using this will make code more manageable and less error prone.
In this case:
class Camera {
public:
CameraSystem() {} // don't need explicit initialization
~CameraSystem() {} // resource in shared_ptr will be deleted automatically
void setGrabber(const std::shared_ptr<FrameGrabber>& newGrabber)
{
_frameGrabber = newGrabber;
}
void startAcquisition() {
_frameGrabber->startAcquisiton(); // note -> instead of .
}
// ....
private:
std::shared_ptr<FrameGrabber> _frameGrabber;
};
And in case of using the factory:
void CameraGui::setGrabberType(int type) {
_myCamera.setGrabber(GrabberFactory::createGrabber(type));
}
class GrabberFactory {
public:
std::shared_ptr<FrameGrabber> createGrabber(int type) {
switch (type) {
case GrabberTypeCoaxA: return {new CoaxGrabberA()};
case GrabberTypeCoaxB: return {new CoaxGrabberB()};
default: throw std::invalid_argument("Invalid grabber type");
}
}
};
As a result, I think I need to use two levels of inheritance, but from
everything I've read, inheritance should be used very rarely, and
composition should be favored.
I can't tell if it can be done without knowing more details, but if you can it seems that it would help making the design cleaner if you would explitely define a Port interface and aggregate the port within FrameGrabber rather than having multiple FrameGrabber implementations. That would favor composition over inheritance and become an implementation of the Strategy pattern.
After that if you wish every ports to have their own specific API then the port settings UI will obviously have to be more complex because it will need to know how to deal with different concrete ports. What would help is to implement various PortSettingsView with a respective controller or view-model for each kind of ports. E.g. BitflowCoaxPortSettingsView driven by BitflowCoaxPortSettingsViewModel, etc. If you aren't familiar with MVC-like architectures I suggest you to learn about them.
The UI would only have to instantiate the proper concrete PortSettingsView and port settings view-model based on the port type. By doing that the view and view-models will always know which kind of port they are configuring making it easy to deal with port-specific behaviors.
There may be other alternatives as well. Perhaps a more abstract approach should be used for configuring ports so that all ports can be configured through the same API. For instance you may use a key-value pair data structure to hold configurations. All ports could then implement something like a public void reconfigure(PortSettings settings) method. I can't tell if it's suitable or not for your problem.
Finally, remember that it's always a good idea to abstract complex creation processes away using a factory. For instance, rather than having a switch statement over the port type directly in the UI to instantiate the correct view and view-model you could delegate that task to a factory.

Conditional Derivation for Unit Testing

I'm writing unit tests that encapsulate a hardware driver (user space), the design pattern that I'm using is as follows:
class uio
{
virtual uint32_t readbit(...);
virtual bool writebit(...);
// other driver related functions
// ...
};
class uio_test : public uio
{
virtual uint32_t readbit(...) override { /* don't talk to hardware, send back test data */ }
virtual bool writebit(...) override { /* don't talk to hardware, write test data */ }
};
class spi : public uio
{
// spi related functions
};
class i2c : public uio
{
// i2c related functions
};
My questions is how to go about making spi and uio properly inherit from either uio OR uio_test depending on the module (real program vs gtest). I've looked at conditionals for example:
template<bool test>
class spi : public std::conditional<test, uio_test, uio>
and this would work in world where all objects were derived simply from the main.
/* main.cpp */
spi<false> s;
s.init();
s.writebit();
/* gtest_main.cpp */
spi<true> s;
ASSERT_TRUE(s.init());
ASSERT_EQ(/* read/write test bits, etc*/);
however the uio derived objects are used in other specialized classes throughout the program, and I cannot see a good way of conditional construction, for example:
class temperature_monitor
{
createBuses();
spi<???>* spictrl_;
};
/* perhaps derive test classes, easy since most high level objects are singletons */
temperature_monitor::createBuses()
{
if (testmode)
spictrl_ = new spi<true>;
else
spictrl_ = new spi<false>;
}
Hope that's clear as mud for everyone. I'll answer a few questions before they're asked:
Q. How about pre-processor conditionals?
A. No, if possible, never.
Q. Why are you writing unit tests for low level bit banging drivers like spi?
A. Why not, there's some internal logic going on, and I'd rather catch errors in a unit test than try and debug a stupid missing 0 for a day.
I think what you want is a strategy pattern. uio provides a non-virtual interface and a pointer to an implementation. You think have a virtual interface and provide either a normal or test instance of that to the uio object, rather than trying to insert inheritance in the middle. Using the strategy pattern even allows you to plug in additional implementations.

A better design pattern than factory?

In the code I am now creating, I have an object that can belong to two discrete types, differentiated by serial number. Something like this:
class Chips {
public:
Chips(int shelf) {m_nShelf = shelf;}
Chips(string sSerial) {m_sSerial = sSerial;}
virtual string GetFlavour() = 0;
virtual int GetShelf() {return m_nShelf;}
protected:
string m_sSerial;
int m_nShelf;
}
class Lays : Chips {
string GetFlavour()
{
if (m_sSerial[0] == '0') return "Cool ranch";
else return "";
}
}
class Pringles : Chips {
string GetFlavour()
{
if (m_sSerial.find("cool") != -1) return "Cool ranch";
else return "";
}
}
Now, the obvious choice to implement this would be using a factory design pattern. Checking manually which serial belongs to which class type wouldn't be too difficult.
However, this requires having a class that knows all the other classes and refers to them by name, which is hardly truly generic, especially if I end up having to add a whole bunch of subclasses.
To complicate things further, I may have to keep around an object for a while before I know its actual serial number, which means I may have to write the base class full of dummy functions rather than keeping it abstract and somehow replace it with an instance of one of the child classes when I do get the serial. This is also less than ideal.
Is factory design pattern truly the best way to deal with this, or does anyone have a better idea?
You can create a factory which knows only the Base class, like this:
add pure virtual method to base class: virtual Chips* clone() const=0; and implement it for all derives, just like operator= but to return pointer to a new derived. (if you have destructor, it should be virtual too)
now you can define a factory class:
Class ChipsFactory{
std::map<std::string,Chips*> m_chipsTypes;
public:
~ChipsFactory(){
//delete all pointers... I'm assuming all are dynamically allocated.
for( std::map<std::string,Chips*>::iterator it = m_chipsTypes.begin();
it!=m_chipsTypes.end(); it++) {
delete it->second;
}
}
//use this method to init every type you have
void AddChipsType(const std::string& serial, Chips* c){
m_chipsTypes[serial] = c;
}
//use this to generate object
Chips* CreateObject(const std::string& serial){
std::map<std::string,Chips*>::iterator it = m_chipsTypes.find(serial);
if(it == m_chipsTypes.end()){
return NULL;
}else{
return it->clone();
}
}
};
Initialize the factory with all types, and you can get pointers for the initialized objects types from it.
From the comments, I think you're after something like this:
class ISerialNumber
{
public:
static ISerialNumber* Create( const string& number )
{
// instantiate and return a concrete class that
// derives from ISerialNumber, or NULL
}
virtual void DoSerialNumberTypeStuff() = 0;
};
class SerialNumberedObject
{
public:
bool Initialise( const string& serialNum )
{
m_pNumber = ISerialNumber::Create( serialNum );
return m_pNumber != NULL;
}
void DoThings()
{
m_pNumber->DoSerialNumberTypeStuff();
}
private:
ISerialNumber* m_pNumber;
};
(As this was a question on more advanced concepts, protecting from null/invalid pointer issues is left as an exercise for the reader.)
Why bother with inheritance here? As far as I can see the behaviour is the same for all Chips instances. That behaviour is that the flavour is defined by the serial number.
If the serial number only changes a couple of things then you can inject or lookup the behaviours (std::function) at runtime based on the serial number using a simple map (why complicate things!). This way common behaviours are shared among different chips via their serial number mappings.
If the serial number changes a LOT of things, then I think you have the design a bit backwards. In that case what you really have is the serial number defining a configuration of the Chips, and your design should reflect that. Like this:
class SerialNumber {
public:
// Maybe use a builder along with default values
SerialNumber( .... );
// All getters, no setters.
string getFlavour() const;
private:
string flavour;
// others (package colour, price, promotion, target country etc...)
}
class Chips {
public:
// Do not own the serial number... 'tis shared.
Chips(std::shared_ptr<SerialNumber> poSerial):m_poSerial{poSerial}{}
Chips(int shelf, SerialNumber oSerial):m_poSerial{oSerial}, m_nShelf{shelf}{}
string GetFlavour() {return m_poSerial->getFlavour()};
int GetShelf() {return m_nShelf;}
protected:
std::shared_ptr<SerialNumber> m_poSerial;
int m_nShelf;
}
// stores std::shared_ptr but you could also use one of the shared containers from boost.
Chips pringles{ chipMap.at("standard pringles - sour cream") };
This way once you have a set of SerialNumbers for your products then the product behaviour does not change. The only change is the "configuration" which is encapsulated in the SerialNumber. Means that the Chips class doesn't need to change.
Anyway, somewhere someone needs to know how to build the class. Of course you could you template based injection as well but your code would need to inject the correct type.
One last idea. If SerialNumber ctor took a string (XML or JSON for example) then you could have your program read the configurations at runtime, after they have been defined by a manager type person. This would decouple the business needs from your code, and that would be a robust way to future-proof.
Oh... and I would recommend NOT using Hungarian notation. If you change the type of an object or parameter you also have to change the name. Worse you could forget to change them and other will make incorrect assumptions. Unless you are using vim/notepad to program with then the IDE will give you that info in a clearer manner.
#user1158692 - The party instantiating Chips only needs to know about SerialNumber in one of my proposed designs, and that proposed design stipulates that the SerialNumber class acts to configure the Chips class. In that case the person using Chips SHOULD know about SerialNumber because of their intimate relationship. The intimiate relationship between the classes is exactly the reason why it should be injected via constructor. Of course it is very very simple to change this to use a setter instead if necessary, but this is something I would discourage, due to the represented relationship.
I really doubt that it is absolutely necessary to create the instances of chips without knowing the serial number. I would imagine that this is an application issue rather than one that is required by the design of the class. Also, the class is not very usable without SerialNumber and if you did allow construction of the class without SerialNumber you would either need to use a default version (requiring Chips to know how to construct one of these or using a global reference!) or you would end up polluting the class with a lot of checking.
As for you complaint regarding the shared_ptr... how on earth to you propose that the ownership semantics and responsibilities are clarified? Perhaps raw pointers would be your solution but that is dangerous and unclear. The shared_ptr clearly lets designers know that they do not own the pointer and are not responsible for it.