Skocz do zawartości

Pytanie o klasy, obiekty, konstruktory, dziedziczenie...


nebraska

Pomocna odpowiedź

Hej

Przerabiam sobie kurs, żeby lepiej zrozumieć klasy, obiekty, dziedziczenie itp i nabrać więcej wiedzy. Zrobiłem taki krótki przykład.

Chodzi mi o kwestie konstruktora w kodzie, obecnie symuluje wartosc z random.

Moje pytanie jak prawidłowo powienien użyć konstruktora i zmiennej int getSensor; z której będa pobierane dane z czujnika, żeby wstawić ją do konstruktora?

Czy w ogóle zmienna ta ma odnosić sie do konstruktora?


/* public    -   metody i atrybuty ktore sa widoczne w wewnatrz klasy i publicznie poza nia. Dostepna klasa publicznie tak, zeby miec dostep z poziomu loopa do atrybutow i metod w klasie.
   private   -   metody i atrybuty ktore sa widoczne tylko w wewnatrz klasy.
   protected -   pelni taka sama funkcje jak private, z ta roznica ze dopuszcza dostep do metod i atrybutow spod klas ktore dziedzicza po klasie bazowej.
*/

using namespace std;

class Temp {

public:

  void funkcja_Publiczna() {
    printf("Temp Na Zew %s\n", "Zimno");
  }

protected:

  int c;
  int getSensor;  // pobieranie danyc z czujnika


  int funkcja_Chroniona() {

    int f = c * 9 / 5 + 32;
    printf("Temp Fahrenheit %d\n", f);
    printf("Temp Celsjusz %d\n", c);
    return f;  // zwraca wartosc
  }
  // konstruktor
  Temp(int a = random(2, 30)) {
    c = a;
  }


private:

  void funkcja_Prywatna() {
    printf("Temp na Zew %d\n", 15);
  }
};

/*Klasa MojaTemp dziedziczy to co jest napisane w klasie Temp.
   " : " operator dziedziczenia klasy 
  Nie dziedziczymy konstruktorow, destruktorow, operatorow*/

class MojaTemp : public Temp {
public:

  void uzyjFunkcjiDziedziczenia() {

    funkcja_Publiczna();
    funkcja_Chroniona();
  }
};


void setup() {
  Serial.begin(115200);
}

void loop() {

  if (Serial.available() > 0) {
    String message = Serial.readStringUntil('\n');

    if (message == "w") {  // Wysylamy polecenie z portu szeregowego.

      MojaTemp dz;
      //dz.funkcja_Chroniona();
      //dz.funkcja_Publiczna();
      dz.uzyjFunkcjiDziedziczenia();
    }
  }
}

 

Link do komentarza
Share on other sites

Doprecyzuj trochę pytanie - co to znaczy że ze zmiennej będą pobierane dane z czujnika? Może chodzi ci o to że w swojej klasie chcesz mieć metodę pobierającą dane z czujnika i wstawiające do tej zmiennej? Nazwa getSensor sugeruje pewną akcję, więc może miałeś na myśli metodę.

Cytat

Czy w ogóle zmienna ta ma odnosić sie do konstruktora?

Raczej w drugą stronę: "czy konstruktor ma coś robić z tą zmienną?" - to już zależy od tego, co chcesz osiągnąć. Opisz trochę dokładniej klasę, którą chcesz zaimplementować.

Link do komentarza
Share on other sites

9 godzin temu, MasterYoda95 napisał:

Może chodzi ci o to że w swojej klasie chcesz mieć metodę pobierającą dane z czujnika i wstawiające do tej zmiennej? 

Dokładnie tak. Zmiennej getSensor, c używam do hermetyzacji danych i chciałbym użyć metody do pobierania danych z czujnika w tej klasie i "uszczelnić w klasie te dane.

Link do komentarza
Share on other sites

2 godziny temu, nebraska napisał:

używam do hermetyzacji danych i chciałbym użyć metody do pobierania danych z czujnika w tej klasie i "uszczelnić w klasie te dane.

Na razie żadnej hermetyzacji tu nie ma. Ale można zrobić inaczej:


public:
int getSensor(void) {return _currentSensor;};

protected: /* albo private */
int _currentSensor;

W Pythonie można użyć dekoratora @property:

@property
def getSensor(self):
  return self.__currentSensor;

(zwróć uwagę na nazwę z dwoma podkreślnikami na początku).

Dobierasz się do tego później po prostu jakby to była zmienna:

   cośtam = sensor.getSensor
  

 

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

@ethanak nie wiem czy dobrze zrozumiałem. Czy finalnie tak może być?

Najważniejsze pytanie. Pisałeś że nie ma żadnej hermetyzacji. Jeśli atrybuty podaje jako private lub protected to nie jest tak, że są "szczelne i tylko w tej klasie?

W moim przykładzie teraz nie mam hermetyzacji? i co z konstrukorem ponieważ tutaj go nie używam.

Nie rozumiem też tej linini. CZym sie rózni ?

int getSensor(void) {

od

int getSensor() {

 

// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);


void setup()
{
  // start serial port
  Serial.begin(115200);
  Serial.println("Dallas Temperature IC Control Library");
  sensors.begin();
}


class Temp {

private: 
float _currentSensor;

public:
float getSensor(void) {

  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
  _currentSensor = sensors.getTempCByIndex(0);
  printf("Temp %f\n", _currentSensor);

  return _currentSensor;
  };
};

void loop()
{ 

if (Serial.available() > 0) {
    String message = Serial.readStringUntil('\n');

    if (message == "w") {  // Wysylamy polecenie z portu szeregowego.

    Temp c;
    c.getSensor();
}}}

 

Link do komentarza
Share on other sites

(edytowany)

Domyślam się, że Koledze chodziło o to, że w poprzedniej wersji kodu dokonałeś hermetyzacji atrybutu przez zadeklarowanie go jako private, ale nie stworzyłeś interfejsu, czyli publicznej metody, która pozwala "dobrać się" do zawartości tej zmiennej spoza klasy. Twój nowy kod już implementuje to rozwiązanie.

Mam jednak uwagę: dlaczego deklarację 

Temp c;

umieściłeś w 

void loop(){
  ...
  }

?

Zadeklaruj ją raz jako zmienną globalną i wywołuj metodę ponownie na tym samym obiekcie w loop().

Dodatkowo sugeruję stosowanie dobrej praktyki nadawania bardziej opisowych nazw - ułatwi to czytanie kodu Tobie oraz szczególnie innym osobom niezaznajomionym z Twoim kodem. Spójrz na poniższy przykład - praktycznie nie wymaga on komentarzy.

class TemperatureSensor{...};

TemperatureSensor temp_sensor;

void setup(){
  temp_sensor.init() // jeśli musimy dokonać jakiejś inicjalizacji, np. nawiązać połączenie
}

void loop(){
  temp_sensor.read()
}

 

Edytowano przez MasterYoda95
błąd w kodzie
  • Pomogłeś! 1
Link do komentarza
Share on other sites

To nie wiedziałem myślałem że taka forma deklaracji Temp c będzie ok.

Teraz będę wiedział żeby do setupa przenieść, a samą metodę wywoływać w loop.

Dziękuję za wskazówki.

 

 

Link do komentarza
Share on other sites

@MasterYoda95 Twój przykład akurat nie zadziała (dlaczego?)

A chodziło mi o coś nieco innego.

Z opisu (dość chaotycznego) wywnioskowałem, że co prawda nie ma możliwości "ręcznego" ustawienia yniku, ale istnieje jakaś metoda która potrafi to zrobić zgodnie z założeniami aplikacji. A te wcale nie są takie oczywiste.

W poprawionym kodzie oczywiście wszystko wydaje się w porządku... ale czy istnienie zmiennej _current_sensor jest konieczne? W tej wersji kodu nie. Ale...

Ale jakie są założenia aplikacji? Jeśli jest to np. stacja pogodowa, to nie są konieczne odczyty czujnika zawsze kiedy pytamy o temperaturę. Przykładowo - wystarczy temperatura z ostatniej minuty. I wtedy getter mógłby wyglądać tak:

float getSensor(void) {
  if (potrzebny_odczyt()) {
    odczytaj_temperaturę();
  }
  return _current_sensor;
}

gdzie potrzebny_odczyt i odczytaj_temperaturę to metody prywatne.

Jaka jest różnica? Po prostu jeśli mamy już w miarę aktualną temperaturę nie musimy dokonywać kolejnego odczytu (który jednak trochę trwa, szczególnie jak się używa byIndex).

Ale pójdźmy dalej.

Załóżmy istnienie okresowo wywoływanej metody loop:

void loop() {
  if (potrzebny_odczyt()) odczytaj_temperaturę();
}

W takiej sytuacji można ograniczyć gettera do postaci pokazanej w pierwszym moim poście.

No to teraz praca domowa: napisać metodę loop tak, aby nie korzytała z wbudowanego w bibliotekę delaya 🙂

Link do komentarza
Share on other sites

(edytowany)

@ethanak rzeczywiście, nie zwróciłem uwagi na zakres.

Przepraszam za zamieszanie - wyedytowałem kod. Wyjaśnienie błędu, jaki popełniłem: jeśli zadeklarujemy zmienną w setup(), będzie ona zmienną lokalną i nie będzie widoczna poza tą funkcją.

Dodam jeszcze że prawidłowe implementacje i wykorzystanie klas można podejrzeć chociażby w dokumentacji bibliotek (najlepiej oficjalnych) - zobacz przykład w dokumentacji biblioteki Servo - obiekt definiowany jest jako zmienna globalna, później metoda inicjalizująca wywołana jest w setup(), a później interakcje z obiektem w loop().

Edytowano przez MasterYoda95
Link do komentarza
Share on other sites

 ...a przykłady "jak nie używać zmiennych private zamiast protected" można znaleźć np. w driverach wyświetlaczy Adafruit 🙂

Link do komentarza
Share on other sites

55 minut temu, ethanak napisał:

@nebraska nie, nie będzie prawidłowy, ale o tym już wspomniałem 🙂

Przeczytaj poprawiony kod Kolegi.

tak jak wspominałęm dopiero poznaje OOP, jeszcze muszę sporo lekcji odrobić.

Próbuje to ogarnać na jakimś przykładzie, żeby lepiej weszło do głowy.

Wprowadziłem zmiany według @MasterYoda95. Zastanwaim się czy takiego zapisu mogę użyc w loop. Pewne to można o wiele lepiej zrobić z wykorzystaniem zmiennej prevTemp którą mam teraz globalnie.

 

// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

float prevTemp;

class Temp {

private:
  float _currentSensor;

public:
  float getSensor(void) {

    Serial.print("Requesting temperatures...");
    sensors.requestTemperatures();  // Send the command to get temperatures
    Serial.println("DONE");
    _currentSensor = sensors.getTempCByIndex(0);
    printf("Temp %f\n", _currentSensor);

    return _currentSensor;
  }
  void initSensor() {
    Serial.println("Dallas Temperature IC Control Library");
    sensors.begin();
  }
};

Temp c;


void setup() {
  // start serial port
  Serial.begin(115200);
  c.initSensor();
}




void loop() {

  if (Serial.available() > 0) {
    String message = Serial.readStringUntil('\n');

    if (message == "w") {  // Wysylamy polecenie z portu szeregowego
      
      c.getSensor();

      if(c.getSensor() != prevTemp) {

        prevTemp = c.getSensor();
         printf("Jesli temp wyslij %s\n", "Apka");

    
      }
    }
  }
}

 

Link do komentarza
Share on other sites

(edytowany)
void loop() {
  static float prevTemp=-100; // zgadnij czemu
  sensor.loop();
  float temp = sensor.getSensor();
  if (temp != prevTemp) {
    prevTemp = temp;
    displayTemperature(temp);
  }
// i coś tam jeszcze
}

@nebraskato akurat totalnie bez sensu.Robisz coś tylko po to żby stwierdzić że się nic nie zmieniło.  Poza tym ne chodziło mi o główną funkcję loop tylko o metodę obiektu  (vide Bounce2)

Napisz metodę loop dla tej klasy tak, żeby była nieblokująca. A kod aplikacji w stylu jak wyżej

 

Edytowano przez ethanak
  • Lubię! 1
Link do komentarza
Share on other sites

(edytowany)

Spr kod działa, ale nie wiem czy dobrze rozumiem Twoje wskazówki. 

Nie blokujący nie bardzo rozumiem czy chodziło o millis?

i nie wiem co oznacz -100?

// Include the libraries we need
#include <OneWire.h>
#include <DallasTemperature.h>
// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

float prevTemp;

class Temp {

public:

  void getSensor() {

  static float prevTemp=-100; // zgadnij czemu
  Serial.print("Requesting temperatures...");
  sensors.requestTemperatures(); // Send the command to get temperatures
  Serial.println("DONE");
    
  float temp = sensors.getTempCByIndex(0);
  printf("Jesli temp wyslij %f\n", temp);

  if (temp != prevTemp) {
    prevTemp = temp;
    //displayTemperature(temp);
    printf("Jesli temp wyslij %s\n", "Apka");
  }
  }
  
  void initSensor() {
    Serial.println("Dallas Temperature IC Control Library");
    sensors.begin();
  }
};

Temp c;


void setup() {
  // start serial port
  Serial.begin(115200);
  c.initSensor();
}



void loop() {

static unsigned long czas;

  if (millis() - czas > 10000) {
    czas = millis();
    
    c.getSensor();

    }
  }

 

Edytowano przez nebraska
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.