Verwendung einer Vorlagenklasse in der Basisklasse von zwei verschiedenen Objekten
-
21-12-2019 - |
Frage
Ich habe ein Problem mit dem Speichern der Vorlagenklasse in der Basis von zwei Objekten.
Angenommen, ich habe eine verallgemeinerte Klasse mit dem Namen ObjectManager definiert als:
template<typename T>
class ObjectManager
{}
Und ich habe eine Basisklasse wie:
class MediaSample
{
public:
MediaSample(ObjectManager<?>* manager){}
private:
ObjectManager<?> mMediaSampleManager;
}
Jetzt deklariere ich zwei weitere gefahrene Klassen von MediaSample, sagen wir:
class AudioSample : public MediaSample
{
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
//...
}
public class VideoSample : public MediaSample
{
public:
VideoSample() : MediaSample(new ObjectManager<VideoSample>())
//...
}
Mein Problem ist die Art von Manager, eingabeparameter von MediaSample
Klasse.
Welcher Typ muss anstelle des Fragezeichens gesetzt werden?Audio, Video oder was?)
zur weiteren Verdeutlichung habe ich die vollständige Quelle von ObjectManager gepostet beachten Sie, dass der Objektmanager eine Abfrage von Medienbeispielobjekten ist und das Medienbeispiel Audio oder Video sein kann
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)
{
}
klasse 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;
};
klassen-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;
};
Lösung
Es kann ziemlich schwierig werden, Kompilierungszeit (Vorlagen) und Laufzeitpolymorphismus (Vererbung) zu mischen.Was Sie tun können:
a) Machen Sie die Basisklasse zu einer Vorlage
template <class T>
class MediaSample {
ObjectManager<T> mMediaSampleManager;
};
class AudioSample : public MediaSample<AudioSample>
In diesem Fall AudioSample
und VideoSample
wird keine gemeinsame Basisklasse haben, was möglicherweise nicht das ist, was Sie wollen.Alternativ können Sie
b) Geben Sie ObjectManager eine Nicht-Template-Basisklasse (eine Schnittstelle)
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>()){}
Beachten Sie auch, dass, wenn Ihr MediaSample
konstruktor akzeptiert einen Zeiger auf neu konstruierte ObjectManager
und Sie kopieren das vermutlich in das Mitgliedsobjekt, Sie müssen daran denken, den Zeiger zu löschen, sonst wird er auslaufen.Sie sollten stattdessen wahrscheinlich nach Wert übergeben.
Andere Tipps
Wie wäre es, MediaSample zu einer Vorlage zu machen:
template <typename T>
class MediaSample
{
public:
MediaSample(ObjectManager<T>* manager){}
private:
ObjectManager<T> mMediaSampleManager;
};
Auf diese Weise können Sie verschiedene Arten von MediaSample ohne abgeleitete Klassen AudioSample und VideoSample .
In diesem Fall MediaSample
muss eine Vorlage sein
template<typename T>
class MediaSample
{
public:
MediaSample(ObjectManager<T>* manager): mMediaSampleManager(manager) {}
private:
ObjectManager<T>* mMediaSampleManager;
}
und XxxSample
muss vom Spezialisierten erben MediaSample
class AudioSample : public MediaSample<AudioSample>
{
public:
AudioSample() : MediaSample(new ObjectManager<AudioSample>()){}
...
}