C++: Übergeordnete Klasseninstanz?

Ich habe da mal ein C++-Problem... Code zur Frage:

#include <Arduino.h>

// Template-Klasse zur Wertspeicherung
template<typename T, T minval, T maxval> class Varz {
  protected:
    T value;
    T min;
    T max;
    std::function<void(unsigned char, T, T)> callback;
  public:
    Varz() : value(0), min(minval), max(maxval), callback(nullptr) {
      static_assert(std::is_integral<T>::value, "Varz is for integral types only!");
     }
    operator T() { return value; }
    T operator=(T v) {
      if (v < min) v = min;
      if (v > max) v = max;
      if (v != value) {
        if (callback) callback('A', value, v);
        value = v;
      }
      return v;
    }
    void setCallback(std::function<void(unsigned char, T, T)> cb) { callback = cb; }
};

// Klasse als Benutzer der Templateklasse
struct UseZ {
  Varz<uint16_t, 10, 1200> wert;
  const char *name;
  UseZ(const char *n) : name(n) {};
};

// Callback-Funktion
void varzCB(unsigned char b, uint32_t oldV, uint32_t newV) {
  Serial.printf("Varz '%c': %d->%d\n", b, oldV, newV);
}

void setup() {
  // Serial setup
  Serial.begin(115200, SERIAL_8N1);
  Serial.println("");

// Eigenständige Instanz der Template-Klasse
  Varz<uint32_t, 10, 254> varz;
  varz.setCallback(varzCB);

  uint32_t preV = 116;
  varz = preV;
  uint32_t postV = varz;
  Serial.printf("preV=%d, varz=%d, postV=%d\n", preV, (uint32_t)varz, postV);

// Zwei Nutzerinstanzen
  UseZ A("Erster");
  UseZ B("Zweiter");

  A.wert.setCallback(varzCB);
  B.wert.setCallback(varzCB);
  A.wert = varz;
  B.wert = 5000;
}

void loop() {
}

Das liefert als Ausgabe

Varz 'A': 0->116
preV=116, varz=116, postV=116
Varz 'A': 0->116
Varz 'A': 0->1200

So weit, so gut.

Unschön: die Callback-Funktion varzCB() wird auch für die beiden Memberinstanzen A.wert und B.wert akzeptiert, obwohl die Signatur anders ist (uint32_t-Argumente, wo wert uint16_t benutzt). Nun ja.

Meine Frage dazu ist: Wie kann ich die beiden wert-Memberinstanzen dazu bringen, zu wissen, in welcher Nutzerinstanz sie sich befinden? Also zum Beispiel den name der Nutzerinstanz an die Callbackfunktion zu übergeben?

jeder Instanz eine ID geben und diese ID dem Callback übergeben.
Z.B. eine static variable auf Klassenebene hochzählen, eine Member variable id im Constructor mit dem aktuellen Zählerstand befüllen. Dann hast eine automatische Durchnummerierung.


class Base {
  protected:
    uint8_t id;
  public:
    Base() {
      id = Base::counter++;
    }
    static uint8_t counter;

    uint8_t getId() {
      return id;
    }
};
uint8_t Base::counter=0;

Base a;
Base b;
Base arr[3];

void setup() {
  Serial.begin(115200);
  Serial.println(a.getId());
  Serial.println(b.getId());
  Serial.println(arr[0].getId());
  Serial.println(arr[1].getId());
  Serial.println(arr[2].getId());
}

void loop() {
  // put your main code here, to run repeatedly:
}

Obs wirklich das gelbe vom Ei ist musst selber wissen ...

edit mit const

/*
   give each instance a unique ID
*/
class Base {
  protected:
    const uint8_t id;
  public:
    Base() : id(Base::counter++) {}
    static uint8_t counter;

    uint8_t getId() {
      return id;
    }
};
uint8_t Base::counter = 0;

Base a;
Base b;
Base arr[3];

void setup() {
  Serial.begin(115200);
  Serial.println(a.getId());
  Serial.println(b.getId());
  Serial.println(arr[0].getId());
  Serial.println(arr[1].getId());
  Serial.println(arr[2].getId());
}

void loop() {
  // put your main code here, to run repeatedly:
}

Danke, aber das passt nicht so wirklich. Die reale Anwendung ist komplexer, und da bekommt die bei mir im Beispiel als Nutzerklasse gezeigte UserZ ihre ID von außerhalb, und zu diesem Zeitpunkt existiert sie schon - mithin sind die Varz-Instanzen schon erzeugt worden, ohne diese ID zu kennen.

Selbstantwort: mit einem public Member, das man im Konstruktor der umgebenden Klasse füllt, klappt es. Kann dann zwar jeder, aber da kann man noch etwas zur Abschirmung dazu programmieren:

#include <Arduino.h>

// Template-Klasse zur Wertspeicherung
template<typename T, T minval, T maxval> class Varz {
  protected:
    T value;
    T min;
    T max;
    std::function<void(unsigned char *, T, T)> callback;
  public:
   const char *id;
    Varz() : value(0), min(minval), max(maxval), callback(nullptr) {
      static_assert(std::is_integral<T>::value, "Varz is for integral types only!");
      id = "NIL";
     }
    operator T() { return value; }
    T operator=(T v) {
      if (v < min) v = min;
      if (v > max) v = max;
      if (v != value) {
        if (callback) callback(id, value, v);
        value = v;
      }
      return v;
    }
    void setCallback(std::function<void(unsigned char *, T, T)> cb) { callback = cb; }
};

// Klasse als Benutzer der Templateklasse
struct UseZ {
  Varz<uint16_t, 10, 1200> wert;
  const char *name;
  UseZ(const char *n) : name(n) {i
    wert.id = n;
  };
};

// Callback-Funktion
void varzCB(const char *b, uint32_t oldV, uint32_t newV) {
  Serial.printf("Varz '%s': %d->%d\n", b ? b : "NIL?", oldV, newV);
}

void setup() {
  // Serial setup
  Serial.begin(115200, SERIAL_8N1);
  Serial.println("");

// Eigenständige Instanz der Template-Klasse
  Varz<uint32_t, 10, 254> varz;
  varz.setCallback(varzCB);

  uint32_t preV = 116;
  varz = preV;
  uint32_t postV = varz;
  Serial.printf("preV=%d, varz=%d, postV=%d\n", preV, (uint32_t)varz, postV);

// Zwei Nutzerinstanzen
  UseZ A("Erster");
  UseZ B("Zweiter");

  A.wert.setCallback(varzCB);
  B.wert.setCallback(varzCB);
  A.wert = varz;
  B.wert = 5000;
}

void loop() {
}

Das gibt dann:

Varz 'NIL': 0->116
preV=116, varz=116, postV=116
Varz 'Erster': 0->116
Varz 'Zweiter': 0->1200

Ich weiß nicht, ob ich Dein Problem verstanden habe, aber hast Du schon mal super.Methode(...) zum Zugriff auf die Elternklasse getestet?

Gruß Tommy

:thinking: Verstehe ich nicht so ganz - die Klasse Varz kennt doch den Typ der umgebenden Klasse UseZ nicht?

Du schreibst in der Überschrift "Übergeordnete Klasseninstanz". Das ist die Eltern- oder Superklasse. Deshalb bin ich davon ausgegangen.
Deswegen habe ich wohl auch Dein Problem nicht wirklich verstanden, weil ich aus der Überschrift einen Zusammenhang vorausgesetzt habe, der nicht existiert.

Gruß Tommy

Ich habe mich mit der Überschrift selbst schwergetan - es geht ja um eine Membervariable einer Klasse, die selbst eine Klasseninstanz ist (die Membervariable).

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.