mikrocontroller.net

Forum: PC-Programmierung c++ Klassenkonstanten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Timm R. (Firma: privatfrickler.de) (treinisch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe immer wieder den Fall, dass ich an member Funktionen eine 
Klassenkonstante übergeben möchte um das erwünschte Verhalten zu 
signalisieren.

Ich mache das so:
public:
    using                   DeviceDirection = int;
    const DeviceDirection   InputDevice = 0;
    const DeviceDirection   OutputDevice = 1;

das ist eigentlich ganz nett und da nur ich selbst das api benutze, 
stört der Nachteil eigentlich auch nicht: Was mich stört ist, dass man 
einer Memberfunktion, zum Beispiel:
void MidiManager::enableDevice(int index, DeviceDirection);

als Konstante (DeviceDirection) jetzt auch einfach einen beliebigen int 
übergeben kann.

Das ist meine Frage. Geht es, und wenn ja, wie, dass ich die Sache so 
gestalten kann, dass ich nur genau die vorgesehenen Konstanten übergeben 
kann und nicht irgendwas konvertierbares?

Mit "nicht kann" meine ich so beiläufig oder aus Versehen, wie in dem 
Beispiel oben, wo ich einfach ->enableDevice(12, 42) schreiben kann 
statt die vorgesehen Konstanten zu verwenden. Ob man das mit Heimtücke 
und Aufwand austricksen kann ist egal, sowas meine ich nicht.

vlg
 Timm

Autor: mh (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Timm R. schrieb:
> ...>
> Das ist meine Frage. Geht es, und wenn ja, wie, dass ich die Sache so
> gestalten kann, dass ich nur genau die vorgesehenen Konstanten übergeben
> kann und nicht irgendwas konvertierbares?
>
> Mit "nicht kann" meine ich so beiläufig oder aus Versehen, wie in dem
> Beispiel oben, wo ich einfach ->enableDevice(12, 42) schreiben kann
> statt die vorgesehen Konstanten zu verwenden. Ob man das mit Heimtücke
> und Aufwand austricksen kann ist egal, sowas meine ich nicht.
>
> vlg
>  Timm

Das was du suchst nennt sich strong type. Einen Einstieg ins Thema gibts 
z.B. hier 
https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/

Autor: Carl D. (jcw2)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verwende statt Konstanten eine
enum class DeviceDirection {
  Input, Output,
}
dann hilft der Compiler gegen "42"

: Bearbeitet durch User
Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> enum

Ja, das ist exakt für sowas gemacht.

Timm R. schrieb:
> Ob man das mit Heimtücke und Aufwand austricksen kann ist egal, sowas
> meine ich nicht.

Das freut mich zu hören, denn viele übertreiben es maßlos, indem sie 
versuchen, ihre API gegen gezielte Sabotage abzusichern statt nur gegen 
versehentliche Falschbenutzung.

Autor: Ralf C. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Carl D. schrieb:
>> enum
>
> Ja, das ist exakt für sowas gemacht.

Ergänzung einer Ungenauigkeit:

In diesem Fall möchte er TO explizit eine starke Typisierung.
Mit dem von dir zitiertem Ausschnitt könnte man denken, dass ein "enum" 
genügen würde.
Ein einfacher enum (unscoped enum) hat implizite Konvertierungen 
von/nach int. Im ursprünglichen Beitrag von Carl D. stand aber "enum 
class", also  ein scoped enum. Diese haben keine impliziten 
Konvertierungen mit int und können nur über den Namen (oder explizite 
Konvertierungen) verwendet werden.

Und das ist, was der TO verwenden möchte.

https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations

Autor: Timm R. (Firma: privatfrickler.de) (treinisch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

vielen Dank an euch alle! Sehr hilfreich und konkret und das Problem ist 
damit gelöst.

Viele liebe Grüße
Timm

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ralf C. schrieb:
> Rolf M. schrieb:
>> Carl D. schrieb:
>>> enum
>>
>> Ja, das ist exakt für sowas gemacht.
>
> Ergänzung einer Ungenauigkeit:
>
> In diesem Fall möchte er TO explizit eine starke Typisierung.
> Mit dem von dir zitiertem Ausschnitt könnte man denken, dass ein "enum"
> genügen würde.
> Ein einfacher enum (unscoped enum) hat implizite Konvertierungen
> von/nach int.

Das ist falsch!
Beim Versuch, folgendes C++-Programm zu übersetzen:
enum DeviceDirection
{
    InputDevice = 0,
    OutputDevice = 1
};

void enableDevice(int index, DeviceDirection dir)
{
}

int main()
{
    enableDevice(12, 42);
}
meldet der Compiler:
enum.cpp: In function ‘int main()’:
enum.cpp:13:24: error: invalid conversion from ‘int’ to ‘DeviceDirection’ [-fpermissive]
     enableDevice(12, 42);
                        ^
enum.cpp:7:6: note:   initializing argument 2 of ‘void enableDevice(int, DeviceDirection)’
 void enableDevice(int index, DeviceDirection dir)
      ^~~~~~~~~~~~

Das ist exakt das, was der TO beschrieben hat, was passieren soll.

> Im ursprünglichen Beitrag von Carl D. stand aber "enum
> class", also  ein scoped enum. Diese haben keine impliziten
> Konvertierungen mit int

Einen klassischen enum kann man nur nach int konvertieren, nicht von 
int.

Autor: Ralf C. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Einen klassischen enum kann man nur nach int konvertieren, nicht von
> int.

Gut.

Der TO sei darauf hingewiesen, dass er sich aussuchen kann ob implizite 
Konvertierungen von enum nach int zulässig sein sollen (unscoped enum), 
oder nicht (scoped enum):
enum       Foo { A = 0, };
enum class Bar { B = 0, };

void fun()
{
  Foo::A + 42;  // ok
  Bar::B + 42;  // error: no match for ‘operator+’ (operand types are ‘Bar’ and ‘int’)
}

Autor: Timm R. (Firma: privatfrickler.de) (treinisch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich erinnere mich. Von enums hatte ich mich für mich persönlich 
verabschiedet, weil mir überhaupt nicht gefiel, dass die Bezeichner aus 
dem enum in den umgebenden Scope durchsickern.

Das hat natürlich den Vorteil das die Bezeichner für die Konstanten 
eleganter sind.

Der scoped enum gefiel mir früher (TM) nicht, weil mir die Bezeichner 
dadurch zu gesprächig waren, aber ich muss sagen, heute gefällt mir das 
eigentlich sogar:
MidiManager::DeviceDirection::Input

Sieht doch eigentlich ganz nett aus. Ich werde also den enum class 
verwenden.

Danke noch mal

vlg
 Timm

Autor: Rolf M. (rmagnus)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Timm R. schrieb:
> ich erinnere mich. Von enums hatte ich mich für mich persönlich
> verabschiedet, weil mir überhaupt nicht gefiel, dass die Bezeichner aus
> dem enum in den umgebenden Scope durchsickern.

> Der scoped enum gefiel mir früher (TM) nicht, weil mir die Bezeichner
> dadurch zu gesprächig waren, aber ich muss sagen, heute gefällt mir das
> eigentlich sogar

Ja, das ist zu einem gewissen Grad auch Geschmackssache. Ich bin ja auch 
nicht generell gegen enum class. Ich mag nur so lange Bandwurmnamen 
nicht so arg - finde sie schwerer zu erfassen, und der zusätzliche 
Bestandteil DeviceDirection:: gibt mit keine Information, die ich ohne 
ihn nicht hätte.

: Bearbeitet durch User
Autor: Timm R. (Firma: privatfrickler.de) (treinisch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Rolf,

Rolf M. schrieb:
> finde sie schwerer zu erfassen,

ja das stimmt. Vielleicht stören sie mich heute deswegen nicht mehr so?

Damals (TM) war ich einfach krasser drauf. Lange Sessions und Hauptsache 
die Tasten klappern :-)

Ich habe aber auch den Fluch, dass ich echt viel hin- und herschalten 
muss zwischen verschiedenen Sprachen, vielen macht das nichts, mir 
schon. Ich komme total schnell wieder raus und verwechsle Idiome etc.

Da können lange und selbsterklärende Namen schonmal eine echte Hilfe 
sein :-)

> und der zusätzliche
> Bestandteil DeviceDirection:: gibt mit keine Information, die ich ohne
> ihn nicht hätte.

Aber geiler Punkt! Danke! Ich denke ich werde das Direction rausnehmen! 
Das ist wirklich über. Das Device hilft mir aber.

vlg
Timm

Autor: Ben W. (ben_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
stichwort strong types wurde ja schon genannt.
die BOOST lib bietet da z.B. einen workarround

mit
BOOST_STRONG_TYPEDEF(int, DeviceDirection)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.