Вызов метода класса из другого метода этого же класса

vasya00
Offline
Зарегистрирован: 30.05.2016

Здравствуйте, уперся в такую проблемку, нужно в одном из методов класса использовать другой метод. Но синтаксиса я не знаю и найти как то не вышло, наверно не так формулирую. Я так понимаю должно использоватся что то вроде self или this?

class buu {
  int a;

  void f1() {
    a++;
   } 
   void f2() {
    f1(); // здесь использовать метод f1
    a++;
   } 
};

 

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

vasya00,можно.Но лучше через внешний обработчик.

#258

vasya00
Offline
Зарегистрирован: 30.05.2016

Выходт ошибка

error: invalid use of non-static member function

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

vasya00. Все же упрямитесь . Хорошо читайте серьезную литературу. Могут еще метры начать писать вам тяжелый для вашего понимания текст. 

vasya00
Offline
Зарегистрирован: 30.05.2016

Даа, тут у меня проблема в другом оказывается, это с библиотекой TTimerList.h от DetSimen, не обрабатывается 

 

hOnceTimer = TimerList.Add(lamp_pin, f1);

Если f1 метод класса. Тут скорее вопрос к DetSimen

Спасибо!

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

Так создайте одиночную функцию-посредник.

  void f(){/*а здесь вызов конкретный метод конкретного класса */}

vasya00
Offline
Зарегистрирован: 30.05.2016

Дак вот дело в том что тут посредник вне класса не поможет, надо как раз чтобы внутри класса это было, без конкретной привязки к экземпляру. Если я правильно выразил мысль..

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

vasya00. значит вы модель системы не проработали. Ведь методы обработки класса вывести из класса и все. Так что лучше прорабатывайте систему, а не усложняйте, то что не надо усложнять.

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

vasya00 пишет:

Дак вот дело в том что тут посредник вне класса не поможет, надо как раз чтобы внутри класса это было, без конкретной привязки к экземпляру. Если я правильно выразил мысль..

У Деда сделана привязка функции, для того, чтобы метод класса могла быть привязана к дедовской либе - эта метод должен быть объявлен с модификатором static. Однако, статические члены класса ничего не знают о конкретном инстансе класса, соответственно, там никакие this не помогут.

Обычно проблема решается передачей дополнительного параметра (в вашем случае - как раз this) в вызывающую сторону. Вызывающая сторона сохраняет этот параметр, и передаёт вам. В общем случае выглядит это так, применительно к вашему примеру:

typedef void (*PCallback)(void* param);

class Caller
{
	public:
	
		void callMe(PCallback callback, void* param)
		{
			callback(param);
		}
	
};

Caller caller;


class SomeClass
{
	public:
		static void calle(void* param)
		{
			SomeClass* ptr = (SomeClass* ) param;
			ptr->doSomething();
		}
		
		void doSomething()
		{
              Serial.print("this is "); Serial.println((uint16_t) this);
			// do the dirty job here!
		}
		
		void bind()
		{
			caller.callMe(calle, this);
		}
	
};



SomeClass some;
SomeClass some2;
some.bind();
some2.bind();

Надеюсь, понятно, что происходит: класс SomeClass имеет общий для всех экземпляров статический метод, который ничего не знает про this. Метод bind передаёт вызывающей стороне (экземпляр класса Caller) указатель на функцию и указатель на экземпляр класса SomeClass. Внутри метода callMe класса Caller просто идёт вызов статического метода calle класса SomeClass, при этом ему передаётся параметр (this, который передал вызывающей стороне экземпляр класса SomeClass). Внутри метода doSomething просто выводится значение this, чтобы убедиться, что метод вызывается для разных экземпляров класса.

Как-то так.

b707
Offline
Зарегистрирован: 26.05.2017

vasya00 пишет:

Даа, тут у меня проблема в другом оказывается, это с библиотекой TTimerList.h от DetSimen, не обрабатывается 

 

hOnceTimer = TimerList.Add(lamp_pin, f1);

Если f1 метод класса. Тут скорее вопрос к DetSimen

 DetSimen тут не поможет.  Метод класса нельзя передавать по ссылке, как обычную функцию, поскольку для каждого экземпляра указатель на этот метод будет свой. Единственное исключение - статические методы, их передавать по ссылке можно, о чем вам компилятор и говорит.

Хотите более подробно - вбейте сообщение компилятора в Гугль и почитайте ссылки - например на Stackoverflow (на английском)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
/**/
class Cl_AAA {
  protected:
    byte num;
  public:
    Cl_AAA(byte n): num(n) {}
    void viev() {
      Serial.println(num);
    }
    void viev(Cl_AAA *p) {
      p->viev();
    }
};
//-------------------------------------
Cl_AAA AAA(/*номер*/1);
Cl_AAA BBB(/*номер*/2);
//-------------------------------------
void setup() {
  Serial.begin(9600);
  AAA.viev();
  AAA.viev(&BBB);
}

void loop() {
}
/**/

Или так

/**/
class Cl_AAA {
  protected:
    byte num;
  public:
    Cl_AAA(byte n): num(n) {}
    void viev() {
      Serial.println(num);
    }
    void viev(Cl_AAA &p) {
      p.viev();
    }
};
//-------------------------------------
Cl_AAA AAA(/*номер*/1);
Cl_AAA BBB(/*номер*/2);
//-------------------------------------
void setup() {
  Serial.begin(9600);
  AAA.viev();
  AAA.viev(BBB);
}

void loop() {
}
/**/

 

Datak
Offline
Зарегистрирован: 09.10.2014

Или так, чтобы уж наверняка ))

/**/
class Cl_AAA {
  protected:
    byte num;
  public:
    Cl_AAA(byte n): num(n) {}
    void viev() {
      Serial.println(num);
    }
    static void viev(Cl_AAA &p) {
      p.viev();
    }
};
//-------------------------------------
Cl_AAA AAA(/*номер*/1);
Cl_AAA BBB(/*номер*/2);
//-------------------------------------
void setup() {
  Serial.begin(9600);

  AAA.viev();
  
  AAA.viev(BBB);     
  BBB.viev(BBB);
  BBB.viev();
  Cl_AAA::viev(BBB);

  // Cl_AAA::viev(); // а так уже не получится
}

void loop() {
}
/**/

 

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

Ты не в скаску попал, в С++ делегатов нет нихрена, а указатели на методы это настолько тонкая вещь, што спицца можно. 

Давай сделаем простейший отомат управления освещением.

TAnalogSensor - это класс любого аналогового датчика, в данном случае - фоторезистора

TDevice - класс исполнительного механизма, в данном случае - реле включения освещения

 

static const int LIGHT_ON_VALUE = 500;   // значение, при котором свет включается
static const int LIGHT_OFF_VALUE = 600;	 // значение, при котором свет выключается

extern TTimerList TimerList;

TAnalogSensor PhotoSensor(A0);	// на А0 у нас фоторезистор
TDevice		  LightRelay(9);    // на 9 пине исполнительное устройство, реле для лампы освещения 

THandle hSensorRead;	       // хэндл таймера чтения 

// функция вызывается таймером раз в секунду
void tmrSensorRead(void) {
	PhotoSensor.Read();			// читаем раз в секунду фоторезистор. Если значение изменится более 
								// чем на Gap попугаев - вызовется evtPhotoChange
}

// функция вызывается самим классом TAnalogSensor, изнутри, если значение на нём изменилось на Gap попугаев
void evtPhotoChange(int avalue) {

	// если темно и не включено - включаем
	if ((avalue < LIGHT_ON_VALUE) && (LightRelay.getState() == enDeviceState::Off)) LightRelay.On();


	// если светло и включено - выключаем
	if ((avalue > LIGHT_OFF_VALUE) && (LightRelay.getState() == enDeviceState::On)) LightRelay.Off();
}


void setup()
{
	PhotoSensor.Gap = 10;			    // гистерезис чтения - 10 попугаев
	PhotoSensor.OnValueChange = evtPhotoChange; // назначаем фоторезистору функцию, которая будет вызываться 
						    // при любом изменении освещенности на величину больше Gap

	TimerList.Add(1000, tmrSensorRead);         // взводим таймер для чтения фоторезистора раз в секунду
}

void loop()
{
	  // тут даже писать ничо не надо, автомат управления освещением работает сам по себе :) 
}

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

vasya00
Offline
Зарегистрирован: 30.05.2016

DetSimen, да но в вашем случае tmrSensorRead не метод класса. Поэтому по таймеру без проблем вызывается. Если например есть множество объектов класса датчиков, и у каждого свое значение PhotoSensor со своим пином подключения и другие свойства, в идеале, нужно методом класса, в "общем виде" включать таймер для каждого конкретного объекта свой, со всеми его свойствами, возможно меняя их при этом. Статический метод тут тоже не подойдет, так как нужен индивидуальный для каждого экземпляра.

В моем случае задумка такая:

#include "TTimerList.h"

extern TTimerList TimerList;
THandle hOnceTimer;

class Swich {
  public:
  const uint32_t signal_length = 100;
  uint8_t lamp_pin;

  void use ();
  void swich ();
  void swich_finish();
};

void Swich::use () { // работа с выключателем, проверка состояний всяких датчиков
// много всего но в конечном итоге:
swich(); // по определенным условиям переключение выключателя в другое состояние
}

void Swich::swich (void) { // метод переключения реализует импульс длительностью signal_length
      hOnceTimer = TimerList.Add(signal_length, swich_finish);   //  взводим таймер
      digitalWrite(lamp_pin, HIGH);       // подаем сигнал на включение
}

void Swich::swich_finish(void) {
  digitalWrite(lamp_pin, LOW);       // выключаем сигнал
  TimerList.Delete(hOnceTimer);    // удаляем таймер
}

Swich sw1;
Swich sw2;
Swich sw3;

void setup() {
}


void loop() {
sw1.use();
sw2.use();
sw3.use();
}

 

DIYMan, как я понял предлогает то что нужно, пытаюсь разобраться...

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

Акей, канешна. Изучай. 

Но в твоей архитектуре - проблема. 

vasya00
Offline
Зарегистрирован: 30.05.2016

DetSimen, возможно, что заметили что не так? Это пока набросок так скажем, в конструкторе будут читаться переменные из конфига, и наверно стоит перейти на опрос датчиков с фиксированным интервалом.. И с вариантом DIYMan, не разобрался, создавать отдельный свой таймер для каждого объекта класса не выйдет хотябы потому что hOnceTimer глобальный и один да и вообще не выходит никак. Думаю может зайти с другой стороны как то..

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

В моей поделке можно одновременно завести 12 таймеров на разные интервалы (для UNO), для Mega - 16. 

vasya00
Offline
Зарегистрирован: 30.05.2016

Да ваша библиотека крута, обязательно буду использовать ее. За нее отдельное спасибо! И всетаки можно как то организовать использования ее внутри класса, с разными объектами? Или стоит вынести этот таймер "за класс"? Так и не могу толком понять..