Comment utiliser une classe basée sur un modèle dans la classe de base de deux objets différents
-
21-12-2019 - |
Question
J'ai un problème avec le stockage de la classe de modèles dans la base de deux objets.
Disons que j'ai une classe généralisée nommée ObjectManager définie comme :
template<typename T>
class ObjectManager
{}
Et j'ai une classe de base comme :
class MediaSample
{
public:
MediaSample(ObjectManager<?>* manager){}
private:
ObjectManager<?> mMediaSampleManager;
}
Maintenant, je déclare deux autres classes pilotées à partir de MediaSample, disons :
class AudioSample : public MediaSample
{
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
//...
}
public class VideoSample : public MediaSample
{
public:
VideoSample() : MediaSample(new ObjectManager<VideoSample>())
//...
}
Mon problème est en quelque sorte directeur, paramètre d'entrée de MediaSample
classe.
Quel type doit être placé au lieu du caractère de point d'interrogation ?(Audio, Vidéo ou quoi ?)
Pour plus de clarification, j'ai publié une source complète d'objectifManager Notez que le gestionnaire d'objets est un sondage sur les échantillons de médias et l'échantillon de médias peut être audio ou vidéo
class BaseMediaSampleManager
{
public:
~BaseMediaSampleManager(){}
virtual INT initialize(INT objectCount) = 0;
protected:
private:
};
template<typename T>
class MediaSamppleManager : public BaseMediaSampleMnager //(based on user2079303 advise)
{
protected:
MediaSamppleManager(void);
MediaSamppleManager(const MediaSamppleManager& manager);
MediaSamppleManager& operator = (const MediaSamppleManager& rhs);
public:
virtual ~MediaSamppleManager(void);
static MediaSamppleManager<T>* instance();
INT initialize(INT objectCount);
// take existing object from object pool and return that object
INT aquireObject(T** object);
// take back in use object to object pool
INT release(T* object);
private:
std::list<T*> mPooledSamples;
INT32 mPooledObjectCount;
INT32 mInUseObjects;
Mutex mPooledSamplesMutex;
static Mutex mSampleManagerObjectMutex;
static MediaSamppleManager<T>* mSampleManagerObject;
};
template<typename T>
Mutex MediaSamppleManager<T>::mSampleManagerObjectMutex;
template<typename T>
MediaSamppleManager<T>* MediaSamppleManager<T>::mSampleManagerObject = NULL;
template<typename T>
MediaSamppleManager<T>* MediaSamppleManager<T>::instance()
{
if (mSampleManagerObject == NULL)
{
ScopedLock<Mutex> guard(mSampleManagerObjectMutex);
if (mSampleManagerObject == NULL)
{
MediaSamppleManager<T>* temp = new MediaSamppleManager<T>();
mSampleManagerObject = temp;
}
}
return mSampleManagerObject;
}
template<typename T>
MediaSamppleManager<T>& MediaSamppleManager<T>::operator=(const MediaSamppleManager<T>& rhs)
{
}
template<typename T>
MediaSamppleManager<T>::MediaSamppleManager(const MediaSamppleManager<T>& manager)
{
}
template<typename T>
INT MediaSamppleManager<T>::release(T* object)
{
ScopedLock<Mutex> guard(mPooledSamplesMutex);
mPooledSamples.push_back(object);
mInUseObjects--;
}
template<typename T>
INT MediaSamppleManager<T>::aquireObject(T** object)
{
ScopedLock<Mutex> guard(mPooledSamplesMutex);
if (mInUseObjects == mPooledObjectCount)
{
// do we need waiting until new sample become available? or
// is it required to create new sample when no free sample exist in pool?
return 2;
}
else
{
T* temp = 0;
temp = mPooledSamples.front();
*object = temp;
mPooledSamples.pop_front();
mInUseObjects++;
}
return 1;
}
template<typename T>
INT MediaSamppleManager<T>::initialize(INT objectCount)
{
if (objectCount<=0)
{
return -1;
}
mPooledObjectCount = objectCount;
mPooledSamples.resize(objectCount);
for (int i = 0 ; i< objectCount ; i++)
{
T* temp = new T(this);
mPooledSamples.push_back(temp);
}
return 1;
}
template<typename T>
MediaSamppleManager<T>::~MediaSamppleManager(void)
{
std::cout << "MediaSampleManager Destroyed \n";
}
template<typename T>
MediaSamppleManager<T>::MediaSamppleManager(void)
:mPooledObjectCount(0)
,mInUseObjects(0)
{
}
classe MediaSample :
class MediaSample
{
public:
// create empty media sample
MediaSample(BaseMediaSampleManager* manager);
virtual ~MediaSample(void);
virtual INT32 rate() = 0;
virtual double frameSize() = 0;
// data size of media sample
virtual INT size();
UINT* data();
ULONG samplingTime();
INT32 addRef();
INT32 release();
private:
UINT8* mMediaSampleBuffer;
// The time sample captured
ULONG mTimestamp;
// length of data
INT mDataLength;
INT mRefCount;
BaseMediaSampleManager* mMediaSampleManager;
};
classe AudioSample :
class PMCAPI AudioSample
:public MediaSample/*<AudioSample>*/
{
public:
AudioSample(MediaSamppleManager<AudioSample>* manager);
~AudioSample();
virtual INT32 rate();
virtual double frameSize();
virtual INT size();
protected:
private:
// in 8,16 KHZ
INT32 mSampleRate;
// Mono or Stereo
INT mChannels;
// Used format ex: PCM,G729,G723,G711A,G711U
INT mCodec;
// ex : 8 bit , 16 bit
INT mBitsPerSample;
};
La solution
Il peut devenir assez difficile de mélanger le temps de compilation (modèles) et le polymorphisme d'exécution (héritage).Ce que tu peux faire:
a) Faire de la classe de base un modèle
template <class T>
class MediaSample {
ObjectManager<T> mMediaSampleManager;
};
class AudioSample : public MediaSample<AudioSample>
Dans ce cas AudioSample
et VideoSample
n'aura pas de classe de base commune, ce qui n'est peut-être pas ce que vous souhaitez.Alternativement, vous pouvez
b) Donner à ObjectManager une classe de base sans modèle (une interface)
class BaseManager{
virtual ~BaseManager(){}
// pure virtual functions that ObjectManager implements
};
template<typename T>
class ObjectManager: public BaseManager{
// implementation
};
class MediaSample {
BaseManager mMediaSampleManager;
// ...
};
class AudioSample: public MediaSample {
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
Notez également que si votre MediaSample
le constructeur accepte un pointeur vers une nouvelle construction ObjectManager
et vous copiez probablement cela dans l'objet membre, vous devez vous rappeler de supprimer le pointeur, sinon il fuira.Vous devriez probablement plutôt passer par valeur.
Autres conseils
Que diriez-vous de faire de MediaSample un modèle :
template <typename T>
class MediaSample
{
public:
MediaSample(ObjectManager<T>* manager){}
private:
ObjectManager<T> mMediaSampleManager;
};
De cette façon, vous pouvez avoir différents types de MediaSample sans avoir besoin de classes dérivées AudioSample et VideoSample.
Dans ce cas MediaSample
doit être un modèle
template<typename T>
class MediaSample
{
public:
MediaSample(ObjectManager<T>* manager): mMediaSampleManager(manager) {}
private:
ObjectManager<T>* mMediaSampleManager;
}
et XxxSample
doit hériter des spécialistes MediaSample
class AudioSample : public MediaSample<AudioSample>
{
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
...
}