"Hallo" wird eher als boolscher Wert anstatt als string interpretiert...

Astimon

PC-Selbstbauer(in)
Hallo,

beim Schreiben eines Programmes, bin ich auf eine sehr unlogische Sache gestoßen.

Zur Verdeutlichung hier die Headerdatei der Klasse, in der das Problem auftritt:

Code:
#pragma once
#include <string>

using namespace std;


class layout
{
public:
  	static string zeile(string text, string ausrichtung = "zentriert");
  	static string zeile(bool voll, char zeichen = '*');
};

Wenn ich nun die Funktion wie folgt aufrufe:

Code:
cout << layout::zeile("Hallo");

wird nun nicht die erste Funktion, sondern die Zweite (die, die einen boolschen Wert und opional ein Zeichen erwartet) ausgeführt.

Verhindern kann ich dies nur wenn ich "Hallo" explizit in einen string umwandle:

Code:
cout << layout::zeile(static_cast<string>("Hallo"));

Das ist ja aber nicht Sinn und Zweck der Überladung...


Kann mir bitte jemand das Verhalten erklären und wie ich das beheben kann?


Ich wäre wirklich dankbar, wenn mir hier jemand helfen kann.

:)
 
Das Problem ist, dass für den Compiler bei der Auflösung der Überladung die boolean-Überladung die beste Entsprechung darstellt.
Hast nicht zufällig den C++-Standard vor dir liegen oder den Stroustrup? Dann wäre es einfacher zu erklären.

Also in Kürze:
Der Compiler schaut erst, ob er mit einer begrenzten Anzahl (vier) von Standard-Umwandlungen zum Ziel einer Entsprechung kommt. In deinem Falle ist das "Hallo" wird in Zeiger auf char umgewandelt und für einen Zeiger gibt es eine Standard-Umwandlung in boolean. Fertig, er hat einen passenden Typ gefunden.
Erst wenn er durch Standard-Umwandlungen nicht zum Ziel gekommen wäre, hätte er weiter im nächsten Schritt nach User-Umwandlungen geschaut. Da wäre er dann auf deinen std::string gekommen.

Was du machen kannst, du fügst noch eine zusätzliche Funktion ein, die einen const char* erwartet und die macht nichts anderes als die std::string Funktion aufzurufen.

Code:
...
static string zeile(const char* text, ausrichtung = "zentriert") {
   return layout::zeile(std::string(text),ausrichtung);
}
 
Ist ne Weile her mit C++ ;) .

Kann es sein, dass dein Aufruf zu keiner der Deklarationen passt?

Zumindest ist das 2. Argument ja leer.
Und C++ ist ein wenig stumpf was Variablen angeht.
Jede Variable kann auf boolean true / false getestet werden, einfach dadurch ob sie von "0" verschieden ist oder nicht.
Ich denke der überprüft den Typ nicht, und nimmt einfach irgendeine passende Methode (in deinem Fall warum auch immer die 2.)
 
Kann es sein, dass dein Aufruf zu keiner der Deklarationen passt?
Das zweite Argument ist dank Vorgabewert optional, d.h. wenn da nix angegeben wird, wird entweder zentriert oder * zugewiesen.


Hast nicht zufällig den C++-Standard vor dir liegen oder den Stroustrup? Dann wäre es einfacher zu erklären.
Was ist das denn?^^ (Meinst du soetwas?)

Aber danke für die Erklärung. Das hab ich sogar verstanden. Logisch ist es für mich nicht wirklich, aber ich kann es nachvollziehen ;)

Ist auch etwas abwegig aus einer Zeichenkette ein Wahrheitswert zu machen.

So langsam wird mir klar wie c++ zu dem Ruf einer schwierigen Sprache kommt^^


Danke nochmal für die Aufklärung, ich wollte schon verzweifeln
 
Ich finde das jetzt nicht komisch oder schwierig. "Hallo" ist halt kein std::string sondern ein const char*. (Technisch gesehen das gleiche wie ein char[]: char[1] == char* +1.) Je nach Compiler wäre hier auch gemeckert worden, dass die Funktion nicht vorliegt. Wie gesagt einfach die Funktion für const char* überladen, fertig.
 
Ich finde das jetzt nicht komisch oder schwierig. "Hallo" ist halt kein std::string sondern ein const char*.
Der Teufel liegt hier im Detail. Hätte Astimon in seiner zweiten Funktion als ersten Parameter nicht boolean sondern int als Typ gewählt, hätte alles so funktioniert, wie er es sich dachte: "Hallo" hätte die std::string Funktion aufgerufen. Weil es keine Reihe von Standardumwandlung gibt, um von Zeiger auf char auf int zu kommen. Der Compiler hätte also dann nachgeschaut, ob es eine eindeutige User-Umwandlung gibt, um von const char* auf std::string zu kommen.

Dass es eine Umwandlung von Zeiger nach boolean gibt, ist nötig, damit man Zeiger in Bedingungen einsetzen kann, zb. if(Zeiger) oder while(Zeiger).

Wie könnte man den Compiler durcheinander bringen?
Code:
class XXX {
public:
    XXX(const char*) {}
}:
...
static string zeile(string text, string ausrichtung = "zentriert");
static string zeile(XXX text, string ausrichtung = "zentriert");
//boolean-Funktion auskommentieren, ansonsten wird die aufgerufen
//static string zeile(bool voll, char zeichen = '*');
...
layout::zeile("Hallo"); //<- Fehler, mehrdeutig layout::zeile(std::string("Hallo")) 
und layout::zeile(XXX("Hallo")) möglich
 
Hallo,

da ihr mir hier so gut geholfen habt, schicke ich gleich noch eine Frage zu dem Thema hinterher:


Theoretisch kann man ja bei Funktionsaufrufen einen Zeiger übergeben um einerseits die übergebene Variable direkt zu bearbeiten, und anderseits um den Kopieraufwand zu verringern.

Ich hab nun gelesen, das wenn man nun noch ein "const" vor die Variable in der Parameterliste setzt (z.B. const int *int_zeiger), die Variable nicht mehr bearbeiten kann, aber der Kopieraufwand auf die Adresse beschränkt bleibt. (Ich weiß, int ist eigentlich nen blödes Beispiel von wegen Kopieraufwand ;) )

Nun steht ja bei "const char *variable" auch nen "const" davor, aber ich kann die Variable dennoch bearbeiten...

Ist hier "const char *" eine Ausnahme, oder hab ich da etwas mit den const-Zeigern falsch verstanden?


Ich danke gleich im Voraus für eure fachkundigen Antworten.

Ich hoffe ich nerve noch nicht. Ich will ja nicht nur c++ programmieren und hoffen das alles funktioniert, sondern auch nachvollziehen und verstehen.
Das Buch mit dem unmerkbaren und unaussprechbaren Namen steht auch schon auf meiner längerfristigen Einkaufsliste.
 
Nun steht ja bei "const char *variable" auch nen "const" davor, aber ich kann die Variable dennoch bearbeiten...
Das hängt davon ab, was du unter bearbeiten verstehst ;-). Es gibt bei Zeigern zwei verschiedene const:
1: const char* var, dh. var ist ein Zeiger auf einen char const und das bedeutet, dass nicht der Zeiger const ist, sondern die Speicherstelle, die er referenziert.
Beispiel:
Code:
void fun1(const char* str)
{
    str[1] = 'A'; //<- Compiler-Fehler
}
Hier würdest du versuchen, das zweite Zeichen im übergebenen String durch ein 'A' zu ersetzen. Und das haut dir der Compiler um die Ohren, weil str[1] ein const char ist.

Was du mit Bearbeiten meintest, war wohl so was, oder?
Code:
void fun2(const char* str)
{
    str = "blabla";
}
Compiliert der Compiler ohne Mucken. Es ist aber sinnlos. Nach dem Aufruf der Funktion fun2 hat sich dein übergebener String nicht verändert. Und wenn du verstanden hast, warum das so ist, bist du schon zehn Schritte weiter im Verständnis von C/C++.

2: char* const var, dh. var ist ein const(anter) Zeiger auf char und das bedeutet, dass wir nicht die Adresse ändern dürfen, auf die str zeigt, aber die Speicherstelle, die durch str referenziert wird. Denn die ist char.
Beispiel:
Code:
void fun3(char * const str)
{
    str[1] = 'A'; //<- kein Problem
    str = "blabla"; //<-Compiler-Fehler, denn der Zeiger ist const
}
Letztere Zuweisung wäre aber (wie vorher schon mal gesagt) sinnlos.

Jetzt kann man beide const natürlich noch verknüpfen als const char* const var, also var ist ein const(anter) Zeiger auf einen char const. Aber naja, einen const(anter) Zeiger (Bsp 2.) sieht man selten, wenn gibt es dafür in C++ Referenzen.
 
Eigentlich sollte "const char *variable" ein Zeiger auf eine konstante Variable sein - und "char * const variable" ein konstanter Zeiger auf eine Variable. Im ersten Fall sollte man zwar den Zeiger ändern können, jedoch nicht den Wert des Objektes, auf das gezeigt wird.
Im zweiten Fall kann die Variable geändert werden, aber nicht der Zeiger (es gibt auch "const char * const variable", ist dann halt alles konstant).

Da ich jetzt leider keinen Zugriff auf nen C++ Compiler habe, kann ich dein Beispiel leider nicht testen :(

Edit: Da war einer schneller ;)
 
Danke für eure Hilfe, ihr seid echt die Besten :)

Ich verstehe nur nicht was dieses Codestück hier macht:

Code:
void fun2(const char* str)
{
    str = "blabla";
}

Wird hier nicht einer Variablen, die nur Speicheradressen aufnehmen kann ein string zugewiesen?

Code:
	int zahl;
	int *zeiger = &zahl;
	zeiger = 7;

Das hier funktionier ja auch nicht. Warum funktioniert dann das erste Codebeispiel?
 
Das hat was mit Pointerarithmetik zu tun:
Code:
char[2] == char* +2

Ergo wird im ersten beispiel einem const char* ein const char* zugewiesen. Es passiert folgendes:

Code:
const char*+0 = b;
const char*+1 = l;
const char*+2 = a;
const char*+3 = b;
const char*+4 = l;
const char*+5 = a;
const char*+6 = \0;

Im zweiten Beispiel weist du einem int* einen int zu. Das funktioniert nicht, weil es hier keine Umwandung über das Array gibt. Arrays sind im Grunde Pointer, das ist das „Geheimnis“. (Um Verwirrung zu vermeiden, Pufferüberläufe zu verhindern, etc. nutzt man in C++ eigentlich eher std::string. char* bzw. char[] sind C-Style.)
 
Zurück