Метод базового класса C ++ с другим аргументом входной структуры для производных классов - PullRequest
0 голосов
/ 04 августа 2020

Я пытаюсь создать базовый класс, определяющий интерфейс для производных классов - скажем, простой класс звуковой оболочки.

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 () как:

const void * settings

Одна возможная реализация может быть:

struct settingsA
{
   int param1;
   int param2;
   ...
};

class AudioStreamA : public AudioStreamBase
{
public:
    ...
    void open(const void* settings) { settingsA * s = (settingsA) settings; ...};
    ...
}

Однако это не похоже на C ++ - я много привык к C и снова начинаю с C ++ через несколько лет. Есть ли лучшее решение? Я думал о создании шаблона для класса или метода, но, поскольку тип является структурой, я не смогу получить доступ к параметрам. И создание сложной конструкции структуры для чтения ее параметров кажется непонятным для чего-то простого, как доступ к нескольким параметрам в структуре.

1 Ответ

0 голосов
/ 04 августа 2020

Вы можете использовать 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)  { } ;
};
...