Инициализация экземпляра класса в другом классе

vlad072
Offline
Зарегистрирован: 01.08.2017

Собсна не получается создать класс на основе двух других. Каким боком вызывать конструкторы этих родительских классов в дочернем? Перебрал несколько пришедших в голову вариантов, ответ компилятора один: no matching function for call to 'InputDev::InputDev()'.

typedef unsigned long dword;

class InputDev {
  public:
    InputDev(int pin) {
      _pin = pin;
      pinMode(_pin, INPUT_PULLUP);
      _oldSt = active();
    }
    bool active(void) {
      return (digitalRead(_pin) == LOW);
    }
    bool rise(void) {
      _state = active();
      _ret = _state && !_oldSt;
      delay(5);
      _ret &= active();
      if (_ret) _oldSt = _state;
      return _ret;
    }
    bool fall(void) {
      _state = active();
      _ret =  _oldSt && !_state;
      delay(5);
      _ret &= !active();
      if (_ret) _oldSt =  _state;
      return _ret;
    }
  private:
    bool _oldSt, _state, _ret;
    int  _pin;
};

class OutputDev {
  public:
    OutputDev(int pin) {
      _pin = pin;
      pinMode(_pin, OUTPUT);
      digitalWrite(_pin, LOW);
    }
    void set(bool val) {
      digitalWrite(_pin, val ? HIGH:LOW);
    }
  private:
    int _pin;
};

class BiDirect {
  public:
    BiDirect(int inPin, int outPin) {
      _inPin = inPin;
      _outPin = outPin;
      _inObj(inPin);
      _outObj(_outPin);
    }
    bool set(bool val) {
      _outObj.set(val);
      return (_inObj.active() == val);
    }
    bool active(void) {
      return _inObj.active();
    }
    bool rise(void) {
      return _inObj.rise();
    }
    bool fall(void) {
      return _inObj.fall();
    }
  private:
    int _inPin;
    int _outPin;
    InputDev _inObj;
    OutputDev _outObj;
};

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017
class BiDirect {
49   public:
50     BiDirect(int inPin, int outPin) {
51       _inPin = inPin;
52       _outPin = outPin;
53       _inObj = new InputDev(inPin);
54

      _outObj = new OutputDev(_outPin);

55     }
56     bool set(bool val) {
57       _outObj.set(val);
58       return (_inObj.active() == val);
59     }
60     bool active(void) {
61       return _inObj.active();
62     }
63     bool rise(void) {
64       return _inObj.rise();
65     }
66     bool fall(void) {
67       return _inObj.fall();
68     }
69   private:
70     int _inPin;
71     int _outPin;
72     InputDev *_inObj;
73     OutputDev *_outObj;
74 };

иначе - никаг

vlad072
Offline
Зарегистрирован: 01.08.2017

request for member 'set' in '((BiDirect*)this)->BiDirect::_outObj', which is of pointer type 'OutputDev*' (maybe you meant to use '->' ?)

в строке 57

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

ну так это ж теперь указатели, и обращайся с ними как с указателями, через ->

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

каоче, либо так 

 _outObj->set(val);

либо так 

 (*_outObj).set(val);

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

и не забудь тогда деструктор в обьемлющем классе прописать.  И лучше всего - виртуальный, на всякий случай.

vlad072
Offline
Зарегистрирован: 01.08.2017

Большое спасибо добрый человек. Теперь ведь переменные с пинами


    int _inPin;
    int _outPin;

больше не нужны я так понимаю. Просто иницируем объкеты прямо в дочернем конструкторе и всё?

class BiDirect {
  public:
    BiDirect(int inPin, int outPin) {
      //_inPin = inPin;
      //_outPin = outPin;
      _inObj = new InputDev(inPin);
      _outObj = new OutputDev(outPin);
    }

 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

естесственно.  Пусь оне сами свои пины хранят. 

vlad072
Offline
Зарегистрирован: 01.08.2017

А зачем мне деструктор? У меня обьекты классов что дочернего что родительских "вечные" ))

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

vlad072 пишет:

А зачем мне деструктор? У меня обьекты классов что дочернего что родительских "вечные" ))

Ну....  иногда, случаеца, что это не так.  С++ лжив и непредсказуем :)  

vlad072
Offline
Зарегистрирован: 01.08.2017

Можно подробней?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

подробней, только в книшках.  

Просто поверь и сделай деструктор.  если он никогда не понадобица, канпилятор его выкинет. 

vlad072
Offline
Зарегистрирован: 01.08.2017

Ещё хочу создать объект для датчика удара. Что я здесь делаю не так?

class Shock {
  public:
    Shock() {
      pinMode(2, INPUT_PULLUP);
      pinMode(3, INPUT_PULLUP);
      _st = 0;
    }
    void reset() {
      _st = 0;
      attachInterrupt(0, hi, FALLING);
      attachInterrupt(1, lo, FALLING);
    }
    void disable() {
      detachInterrupt(0);
      detachInterrupt(1);
    }    
    byte state() {
    if (_st == 1) 
      for (dword _begin = millis(); (millis() - _begin) < 100;)
        if (_st > 1) return 2;
    if (_st > 2) _st = 2;
    return _st;
    }
  private:
    static volatile byte _st;
    static void hi() {
      _st = 2;
      detachInterrupt(0);
    }
    static void lo() {
      _st |= 1;
      detachInterrupt(1);
    }
};

sketch/hw.h:92: undefined reference to `Shock::_st'

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vlad072 пишет:

Каким боком вызывать конструкторы этих родительских классов в дочернем? 

Кто Вам сказал, что он у Вас дочерний? Это два независимых класса. Никакого отношения к дочернему не имеют.

Ну, как работать с указателями Вам уже показали. Если же хотите сделать так, как было у Вас (без указателей), то тут есть два варианта (вернее, вариантов больше, но простых два).

1. Инициализируйте члены перед выполнением конструктора. Для этого, в скетче из стартового сообщения, вместо строк №№ 50-55 пишите

    BiDirect(int inPin, int outPin) : _inObj(inPin), _outObj(outPin) {
      _inPin = inPin;
      _outPin = outPin;
    }

и всё будет.

2. Заведите у  InputDev/OuputDev коснтуктор по умолчанию, а нынешнюю инициализацию перенесите в init. Т.е. заводите конструктор InputDev(){}. Также заводите метод void Init(int inPin) {_pin = _inPin; } и используете этот Init для инициализации.

Первое проще, по-моему.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
class Cl_AAA {
  protected:
    byte data;
  public:
    Cl_AAA (byte d): data(d) {}
};
class Cl_BBB {
  protected:
    Cl_AAA AAA1,AAA2;
  public:
    Cl_BBB (): AAA1(5),AAA2(6) {}
};
//-------------
Cl_BBB BBB;
//---------------------
void setup() {
}

void loop() {
}

 

vlad072
Offline
Зарегистрирован: 01.08.2017

Такое будет работать?

class InputDev {
  public:
    InputDev(int pin) {
      _pin = pin;
      pinMode(_pin, INPUT_PULLUP);
      _oldSt = active();
    }
    bool active(void) {
      return (digitalRead(_pin) == LOW);
    }
    bool rise(void) {
       _state = active();
      _ret =  !_oldSt && _state;
      delay(5);
    }
    bool fall(void) {
      _state = active();
      _ret =  _oldSt && !_state;
      delay(5);
      _ret &= !active();
      if (_ret) _oldSt =  _state;
      return _ret;
    }
  private:
    bool _oldSt, _state, _ret;
    int  _pin;
};
 
class OutputDev {
  public:
    OutputDev(int pin) {
      _pin = pin;
      pinMode(_pin, OUTPUT);
      digitalWrite(_pin, LOW);
    }
    void set(bool val) {
      digitalWrite(_pin, val ? HIGH:LOW);
    }
  private:
    int _pin;
};

class BiDirect: public Input, Output {
  public:
    BiDirect(int inPin, int outPin) : InputDev(inPin), OutputDev(outPin) { }
    bool set(bool val) {
      OutputDev::set(val);
      return (active() == val);
};

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vlad072 пишет:

Такое будет работать?

Что или кто мешает самому запустить и посмотреть?

Конечно, не будет.

vlad072
Offline
Зарегистрирован: 01.08.2017

Мешает отсутствие ардуинки под рукой. Наследую два класса с перекрытием одного метода <set> и конструктора. Что не правильно?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Зачем ардуинка? Скомпилировать и посмотреть на ошибки компиляции можно и без неё.

Например, что означают слова Input, Output в строке № 43? Таких классов в программе нет, а что эти слова тогда там делают?

vlad072
Offline
Зарегистрирован: 01.08.2017

Упс.. извиняюсь, не всё переобозвал, пытался сохранить прежние имена для ясности. Компилируется без ошибок. Вобщем вот:

class Input {
  public:
    Input(int pin) {
      _pin = pin;
      pinMode(_pin, INPUT_PULLUP);
      _old = active();
    }
    bool active(void) {
      byte _cntr;
      do {
        _cntr = 0;
        for (byte _i = 1; _i <= 5; _i++) _cntr += (int)digitalRead(_pin);
      } while ((_cntr > 0) && (_cntr < 5));
      return(_cntr == 0);
    }
    bool rise(void) {
      bool _state = active();
      bool _ret = _state && !_old;
      _old = _state;
      return _ret;
    }
    bool fall(void) {
      bool _state = active();
      bool _ret = !_state && _old;
      _old = _state;
      return _ret;
    }
  private:
    bool _old;
    int  _pin;
};

class Output {
  public:
    Output(int pin) {
      _pin = pin;
      pinMode(_pin, OUTPUT);
      digitalWrite(_pin, LOW);
    }
    void set(bool val) {
      digitalWrite(_pin, val ? HIGH:LOW);
      _state = val;
      _actual = false;
    }
    void pulse(dword timeout) {
      _begin = millis();
      _timeout = timeout;
      _actual = true;
    }
    void processing() {
      if (_actual) {
        bool _timely = (millis() - _begin) < _timeout;
        if (_timely && !_state) { digitalWrite(_pin, HIGH); _state = true;}
        if (!_timely && _state) { digitalWrite(_pin, LOW); _state = false; _actual = false; }
      }        
    }
  private:
    int _pin;
    dword _begin = 0;
    dword _timeout = 0;
    bool _actual = false;
    bool _state = false;
};

class InOut : public Input, Output {
  public:
    InOut(int inPin, int outPin) : Input(inPin), Output(outPin) { }
    bool set(bool val) {
      Output::set(val);
      return (active() == val);
    }
};

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, явный ляп Вы исправили, а будет ди корректно работать, запустите - посмотрите. Откуда мне знать, если я даже не знаю, что она должна по задумке делать. Запустите, посмотрите, будут вопросы - спросите.

vlad072
Offline
Зарегистрирован: 01.08.2017

Хотел бы узнать, наследование правильно сделал, класс BiDirect описан корректно? Бедет ли наследовать все методы родителей? Корректно ли создаст их экземпляры при "созданни себя"? Корректно ли заменил метод <set>?

Делаю такое впервые, поэтому успешная компиляцтя ессено ничего не гарантирует. В интернетах есть только примеры наследования одного класса, но про "два в одном" ничего не нашёл. Интересно мнение опытных.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

У Вас терминология непонятная. То у Вас посторонние классы - дочерние, то при наследовани создаются экземпляры. 

Как создавать экземпляры я Вам написал в посте #13 - надеюсь, Вы его читали. 

А здесь создаётся оди экземпляр класса, у которого два родителя. Конструкторы родителей на превый взгляд вызываются нормально.

vlad072
Offline
Зарегистрирован: 01.08.2017

Терминология как и понимание синтаксиса хромает к сожалению ))) Задача такая:

К пинам подключены "устройства", часть - "контролируемые", которые только читаем, чать "управляемые" в которые только пишем , часть "IO" в которые по одному пину пишем из другого читаем. При этом нужно иметь возможность отслеживать фронты, спады на входах, фильтровать "дребезг" переходных состояний, "писать в выход" импульсы произвольной длинны. Поскольку логика работы со всеми этими устройствами довольно однотипнае, решил глянуть в сторону классов (куда никогда до этого не глядел), иначе основной код превращается в сущий хаос и неразбериху. Вот такакя вот задача. Надеюсь понятно выразился )

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

vlad072. Вы должны отличать наследование  и просто втавки в класс.  Вот в классе к примеру переменая int. И скорее нет необходимости ее наследовать с какого-то мифического класса переменных.

vlad072 пишет:
К пинам подключены "устройства", часть - "контролируемые", которые только читаем, чать "управляемые" в которые только пишем , часть "IO" в которые по одному пину пишем из другого читаем. При этом нужно иметь возможность отслеживать фронты, спады на входах, фильтровать "дребезг" переходных состояний, "писать в выход" импульсы произвольной длинны. Поскольку логика работы со всеми этими устройствами довольно однотипнае, решил глянуть в сторону классов (куда никогда до этого не глядел), иначе основной код превращается в сущий хаос и неразбериху. Вот такакя вот задача. Надеюсь понятно выразился )
Создайте три независимых класса("контролируемые","управляемые","IO") и дальше оперируйте ими как объектами.