Reputation: 3052
I got problems formulating it precisely so I left more general description in the title (if you have more precise description of the problem, please comment, I'll edit the title).
The problem: Two classes AudioStream
and VideoStream
are derived from base class MediaStream
which has some common for audio and video stream methods, but is not intended to be used as-is. Consequently, there are two classes AudioStreamSettings
and VideoStreamSettings
which are derived from MediaStreamSettings
and passed to the constructors of their corresponding stream classes. MediaStreamSettings
stores settings common for audio and video, and base class MediaStream
accesses this data. The question is: what would be the best way to design this hierarchical relationship between base classes of streams and settings?
I can think of a quick solution like the following:
class MediaStream {
public:
MediaStream(const MediaStreamSettings& settings){
// do nothing, let derived classes initialize settings_
// note: I feel guilty for doing this...
}
virtual ~MediaStream(){}
protected:
std::shared_ptr<MediaStreamSettings> settings_;
};
class VideoStream : public MediaStream {
public:
VideoStream(const VideoStreamSettings& settings):
MediaStream(settings)
{
settings_ = std::make_shared<VideoStreamSettings>(settings);
}
void doSomething(){
int s1 = std::dynamic_pointer_cast<VideoStream, MediaStream>(settings_)->getVideoStreamSetting1();
...
}
};
class AudioStream : public MediaStream {
public:
AudioStream(const AudioStreamSettings& settings):
MediaStream(settings)
{
settings_ = std::make_shared<AudioStreamSettings>(settings);
}
}
To summarize I'm not comfortable with two things in this approach:
settings_
in base class (should I make it abstract to calm myself?)dynamic_pointer_cast
every time I need to access settings in derived classes (should I make a method wrapper for this?)Upvotes: 0
Views: 246
Reputation: 907
Since MediaStream should not be used as-is, making it an abstract class should be acceptable (and desirable). Thus providing implementation (which includes class members) is pointless.
class IMediaStream {
public:
virtual ~IMediaStream() {}
virtual void play() = 0;
virtual std::shared_ptr<MediaSettings> getSettings() = 0;
private:
IMediaStream() {}
};
template<Setting>
class MediaStream : public IMediaStream {
public:
MediaStream(const Setting& settings){
settings_ = std::make_shared<Setting>(settings);
}
virtual ~MediaStream() {}
virtual void play() override {
// Implementation here
}
virtual std::shared_ptr<MediaSettings> getSettings() override {
return std::dynamic_pointer_cast<Setting, MediaSettings>();
}
private:
std::shared_ptr<Setting> settings_;
}
// Alternatively you can inherit or specialize
// the template to add your implementation
typedef MediaStream<VideoStreamSettings> VideoStream;
typedef MediaStream<AudioStreamSettings> AudioStream;
Upvotes: 1
Reputation: 217750
One solution is to not store data in MediaStream
and add a virtual method
virtual const MediaStreamSettings& GetMediaStreamSettings() const = 0;
Upvotes: 1