Reputation: 2313
I'm working on a project where I need to be able to dynamically spawn objects of a type called Audio_Device
or types that derive from Audio_Device
. I have been trying to use a "Factory" pattern in order to achieve this. The idea is that a "ID" string will get registered with the factory as well as a corresponding function pointer to a function that exists inside of Audio_Device
that spawns a new device. When I call factory->Create_Device("IdString");
the code should look up the function pointer associated with the ID and call the function via the function pointer and return a new object of the proper type.
I will apologize now for the mass of code to come:
Here is the device factory header:
class Device_Factory
{
public:
Device_Factory();
virtual ~Device_Factory();
void Register_Device(std::string id,pDevice_Creation_Function pCreateDeviceFunction);
Audio_Device* Create_Device(std::string id,Memory::Pool* pool=nullptr);
private:
std::map<std::string,pDevice_Creation_Function>*m_pFactory_Map;
//map used to get function pointer that will spawn an instance of the class specified with the string key.
std::map<std::string,pDevice_Creation_Function>::iterator iter;
};
and the implementation:
Device_Factory::Device_Factory()
{
m_pFactory_Map = new std::map<std::string,pDevice_Creation_Function>();
}
Device_Factory::~Device_Factory()
{
delete m_pFactory_Map;
}
void Device_Factory::Register_Device(std::string id,pDevice_Creation_Function pCreateDeviceFunction){
m_pFactory_Map->insert(std::make_pair(id,pCreateDeviceFunction));
}
Audio_Device* Device_Factory::Create_Device(std::string id,Memory::Pool* pool){
iter=m_pFactory_Map->find(id);
pDevice_Creation_Function p= iter->second;
//some sort of call to function pointer here
}
And now the Audio_Device
code:
class Audio_Device;
typedef Audio_Device* (Audio_Device:: *pDevice_Creation_Function)(Memory::Pool* pool);
class Audio_Device: public Device
{
protected:
virtual Audio_Device* Create_Device(Memory::Pool* pool=nullptr);
/*Functions to describe how the class modifies the audio signal*/
bool GetNeedsInputWrite();
void SetNeedsInputWrite(bool value);
bool GetWillModifySignal();
void SetWillModifySignal(bool value);
/*--------------------------------------------------------------*/
private:
bool m_requiresInputWriteToProcess;
bool m_willModifySignal;
std::map<std::string, void*>* m_pParameters;
std::map<std::string, void*>::iterator iter;
/*Read and write buffers*/
Audio::AudioRingBuffer* m_pInputBuffer;
Audio::AudioRingBuffer* m_pOutputBuffer;
/*----------------------*/
public:
Audio_Device(Memory::Pool* pool=nullptr);
virtual ~Audio_Device();
virtual void* Process(void* data);
void SetBuffers(Audio::AudioRingBuffer* input,Audio::AudioRingBuffer* output);
/*Parameter management*/
void RegisterParameter(std::string id,void* location);
void* GetParameter(std::string id);
/*--------------------*/
constexpr static const pDevice_Creation_Function Device_Creation_Function=&Audio_Device::Create_Device;
};
template<typename ParameterType> void AssignToDeviceParameter(std::string parameter_id,ParameterType value,Audio_Device* device)
{
*(ParameterType*)device->GetParameter(parameter_id)=value;
}
}
And Implementation:
Audio_Device::Audio_Device(Kraken::Memory::Pool* pool):Device::Device(pool)
{
m_pParameters = new std::map<std::string, void*>();
SetNeedsInputWrite(false);
SetWillModifySignal(true);
m_pInputBuffer=m_pOutputBuffer=nullptr;
}
Audio_Device::~Audio_Device()
{
delete m_pParameters;
m_pParameters=nullptr;
m_pInputBuffer=nullptr;
m_pOutputBuffer=nullptr;
}
void Audio_Device::SetBuffers(Audio::AudioRingBuffer* input,Audio::AudioRingBuffer* output){
if (input!=nullptr) {
m_pInputBuffer=input;
}
if (output!=nullptr) {
m_pOutputBuffer=output;
}
}
void* Audio_Device::Process(void* data)
{
/*The Basic Process:
Wipes input buffer and writes silence to the output buffer.
the void* data can be used to pass information to the function. in this implementation the function merely passes the adress of the data back in order to complete the return for the function.
*/
m_pInputBuffer->Flush();
Audio::Sample_Stereo_d samp;
samp.m_Channel_1=0;
samp.m_Channel_2=0;
for (int i =0; i<m_pOutputBuffer->Buffer_Size(); ++i) {
m_pOutputBuffer->Push(&samp);
}
return data;
}
bool Audio_Device::GetNeedsInputWrite(){
return m_requiresInputWriteToProcess;
}
void Audio_Device::SetNeedsInputWrite(bool value){
m_requiresInputWriteToProcess=value;
}
bool Audio_Device::GetWillModifySignal(){
return m_willModifySignal;
}
void Audio_Device::SetWillModifySignal(bool value){
m_willModifySignal=value;
}
void Audio_Device::RegisterParameter(std::string id,void* location){
m_pParameters->insert(std::make_pair(id, location));
}
void* Audio_Device::GetParameter(std::string id){
iter= m_pParameters->find(id);
return iter->second;
}
Audio_Device* Audio_Device::Create_Device(Memory::Pool* pool){
return new(pool)Audio_Device(pool);
}
I have some namespace business and memory pooling going on so please ignore that. The goal is to be able to have code like this:
Device_Factory* factory = new Device_Factory();
factory->Register_Device("ID", Audio_Device::Device_Creation_Function);
That will register the parameter.(this works right now)And then have the Audio_Device* Create_Device(std::string id,Memory::Pool* pool=nullptr);
function perform code like this:
Audio_Device* Device_Factory::Create_Device(std::string id,Memory::Pool* pool){
iter=m_pFactory_Map->find(id);
pDevice_Creation_Function p= iter->second;
//where pDevice_Creation_Function is a member function pointer.
//and then somehow call it to return a new object.
}
My main issue is that all of the various member function call syntax's i have found do not seem to work. For example (device.*Device_Creation_Function)(args)
does not work for me.
So what is the proper way to call a member function pointer? or what is a better way to achieve the concept i have attempted to describe?
Any help of any kind would be great, and let me know if i can provide clarification because I know that i am throwing a stack of code at you.
Thanks
Upvotes: 0
Views: 900
Reputation: 283694
Member function pointers work fine with virtual functions, but you need an object to call them on.
Which conflicts with the purpose of using that function to create the object in the first place.
Upvotes: 1
Reputation: 17
They not work because they really not works in such situation. The "device" creation function should be like usual non-member function. It may be a static member (clearly, trivial wrapper for "new"). No member function call syntax should be used, no "virtual constructor" are existing :-) Second, it may be better simple construct the desired object of proper derived class as necessary (by "new"). Do you sure you really need the "Factory" and string id's? Also the map which constructed by "new" in constructor and deleted in destructor may be better the data member, not the pointer... And parameters map in AudioDevice are some questionable. Do really AudioDevice class should manipulate unknown parameters of type void*? May be they are members of derived class (where they will have an appropriate names and proper types and will be properly manipulated)?
Upvotes: 1