我正在尝试创建一个基类,定义派生类的接口,比如一个简单的音频包装类。
class AudioStreamBase
{
public:
virtual
~AudioStreamBase(void);
virtual void
open(const void * settings) = 0;
virtual void
start(void) = 0;
virtual void
stop(bool force) = 0;
virtual void
close(void) = 0;
virtual int
recover(int err) = 0;
virtual int
readFrames(void * buffer) = 0;
virtual int
writeFrames(void * buffer) = 0;
virtual void
printConfig(void) = 0;
};
由于不同的实现可能在Linux/Win/嵌入式系统中接受不同的配置参数,我将open((的输入参数定义为:
constvoid*设置
一种可能的实现方式是:
struct settingsA
{
int param1;
int param2;
...
};
class AudioStreamA : public AudioStreamBase
{
public:
...
void open(const void* settings) { settingsA * s = (settingsA) settings; ...};
...
}
然而,这似乎不是很C++——我已经习惯了很多C,几年后我又开始使用C++了。有更好的解决方案吗?我正在考虑对类或方法进行模板化,但由于类型是一个结构,我将无法访问参数。构建一个复杂的结构构造来读取它的参数对于访问结构中的几个参数这样简单的事情来说似乎很模糊。
您可以使用CRTP将派生类注入基类。然后,您可以定义一个特性帮助器来定义,例如,某些派生类必须使用哪些设置。诚然,这有点冗长,但现在您的代码是类型安全的。
如果您需要基类是非模板的,那么您可以将除open
之外的所有内容提取到非模板顶部基类中。
class AudioStreamA;
struct settingsA;
template<class T>
struct AudioStreamTraits;
template<>
struct AudioStreamTraits<AudioStreamA> {
using Settings = settingsA;
};
template<class Derived>
class AudioStreamBase
{
protected:
using StreamTraits = AudioStreamTraits<Derived>;
using Settings = typename StreamTraits::Settings;
public:
virtual
~AudioStreamBase() = default;
virtual void
open(const Settings& settings) = 0;
//...
};
struct settingsA
{
int param1;
int param2;
};
class AudioStreamA : public AudioStreamBase<AudioStreamA>
{
using Base = AudioStreamBase<AudioStreamA>;
using Base::Settings;
public:
void open(const Settings& settings) override { };
};
int main() {
AudioStreamA s;
settingsA settings;
s.open(settings);
return 0;
}
请参阅此处的代码示例
但是,如果您只需要派生类中的设置,那么您可以简单地用派生类的构造函数替换open
:
class AudioStreamBase
{
public:
virtual
~AudioStreamBase() = default;
// ....
};
struct settingsA
{
int param1;
int param2;
};
class AudioStreamA : public AudioStreamBase
{
public:
AudioStreamA(const settingsA& settings) { } ;
};