Im Gegensatz zu den meisten
MFC-Klassen, die in der Vererbungshierarchie der Klassen auf CObject
basieren, besitzt CString
keine Oberklasse, sondern steht für sich
alleine. CString
gehört zu den sogenannten Simple Value Typen innerhalb der
MFC-Familie. Weitere Simple Value Typen
sind CPoint, CRect,
CSize, CTime und CTimeSpan.
CString verwendet als Grundlage den universellen Datentyp TCHAR. Wenn die Benutzung von Unicode festgelegt wurde, entspricht TCHAR dem Datentyp wchar_t (zwei Byte pro Zeichen). Ist dies nicht der Fall, dann entspricht TCHAR dem klassischen char (ein Byte pro Zeichen).
Der Compiler wandelt in eine Unicode-Zeichenfolge um, wenn _UNICODE definiert ist, andernfalls in eine ANSI-Zeichenfolge. Das Makro _T wandelt das Zeichenfolgenliteral "Hallo" in die Form L"Hallo" um. Der Compiler sieht diesen String dann als eine Unicode-Zeichenfolge an.
In der Datei tchar.h findet man hierzu diesen Sourcecode:
#ifdef _UNICODE(Anmerkung: ## ist der "Token-Einfügungsoperator" oder "Vereinigungsoperator")
Damit wir uns hier auf die
MFC-Klasse CString
konzentrieren können, verwenden wir nachfolgend
Konsolenanwendungen.
Man bindet hierzu lediglich die Datei afx.h in das Programm
ein.
Probieren wir es aus:
#include
<afx.h> #include <iostream > using namespace std; int main() { CString strZeichenfolge1 = _T("Hallo"); CString strZeichenfolge2( _T("Welt!") ); CString strZeichenfolge3 = strZeichenfolge1 + _T(" ") + strZeichenfolge2; cout << LPCTSTR ( strZeichenfolge3 ) << endl; strZeichenfolge3.MakeReverse(); cout << "Invertiert: " << LPCTSTR ( strZeichenfolge3 ) << endl; strZeichenfolge3.MakeReverse(); cout << "Erneut invertiert: " << LPCTSTR ( strZeichenfolge3 ) << endl; cout << "Laenge der Zeichenfolge: " << strZeichenfolge3.GetLength() << endl; cout << "Siebter Buchstabe: " << strZeichenfolge3.GetAt(6) << endl; cout << "Die 3 ersten Buchstaben: " << LPCTSTR( strZeichenfolge3.Left(3) ) << endl; cout << "Die 3 letzen Buchstaben: " << LPCTSTR( strZeichenfolge3.Right(3) ) << endl; cout << "Die 5 mittleren Buchstaben: " << LPCTSTR( strZeichenfolge3.Mid(3,5) ) << endl; CString strZeichenfolge4(_T("schoene neue ")); for (int i=0; i<13; ++i) strZeichenfolge3.Insert(i+6, strZeichenfolge4[i]); cout << "Erweiterte Zeichenfolge: " << LPCTSTR( strZeichenfolge3 ) << endl; while (cin.get() != '\n'); // Damit die Konsole bis zur Eingabe von Enter sichtbar bleibt return 0; } |
Damit die Ausgabe mittels
cout problemlos klappt, müssen wir das CString-Objekt zunächst in
ein
character-Array umwandeln.
Dies erfolgt mit dem Operator LPCTSTR(...).
Hierbei ist LPCTSTR (Long Pointer to
a Constant String; das T deutet auf die Abhängigkeit von _UNICODE hin)
nichts anderes als eine andere Bezeichnung für das in C übliche const
char * bzw. const
wchar *, also ein Zeiger auf einen char- oder wchar-String, je
nachdem, wie es definiert ist. Bezüglich Unicode finden Sie z.B. hier
einen Einstieg und weitere Informationen.
Die
Klasse CString
verfügt über eine Reihe nützlicher Member-Funktionen:
CString::GetLength( ) liefert die Länge der Zeichenfolge als int.
CString::GetAt( int index ) liefert den Buchstaben an der Stelle index+1 der Zeichenfolge als TCHAR, da die Zählweise bei 0 beginnt.
CString::MakeReverse( ) kehrt die Zeichenfolge um. Interessant für Personen, die gerne rückwärts lesen.
Wer die Programmiersprache BASIC kennt, der findet hier sicher erfreut die Analoga zu LEFT$, RIGHT$ und MID$:
CString::Left( int
nCount )
CString::Right( int
nCount )
CString::Mid( int
nFirst ) bzw.
CString::Mid( int
nFirst, int nCount )
Ein Objekt der Klasse CString sollte man sich nicht als Zeiger auf das erste Zeichen eines Strings, sondern als richtiges String-Array vorstellen.
Dies wird durch die zeichenweise Einfügung des Strings "schoene neue " an der i+6-ten Stelle im "Array" deutlich.
Der Operator CString::operator[
] steht hier stellvertretend für CString::GetAt(...). Diese
Schreibweise ist analog zum Ansprechen eines Elementes in einem Array.
Wie Sie sehen, ist der
Umgang mit dem MFC-Typ CString
relativ unkompliziert und intuitiv. Versuchen
Sie in der Windows-Programmierung mit MFC komplett auf diesen Typ
umzusteigen,
damit Sie sich die mit character-Arrays verbundenen Probleme ersparen.
Einen kompletten Überblick
über die verschiedenen Member-Funktionen der MFC-Klasse CString erhält man
in MSDN. Wer sich intensiv mit dem inneren Mechanismus von CString
auseinander
setzen will, findet den Sourcecode in folgenden Dateien:
afx.h (Klassendefinition), strcore.cpp und strex.cpp (MFC Sourcecode)
Seit der Version MFC 4.0
verfügt die Klasse CString über
einen sogenannten Referenzzähler.
Mit
dieser Technik werden unnötige Kopien beim Erstellen und Zuordnen
vermieden.
Man verringert auf diese Weise den Speicherbedarf und erhöht die
Geschwindigkeit. Dieser Mechanismus greift z.B. bei folgendem Code:
CString str1
("Hallo Welt!");
CString
str2 = str1;
In den beiden Variablen str1
und str2
steht der gleiche Text. Solange keiner der Strings durch
Schreiben verändert
werden muss, wird die von allen Stringvariablen genutzte Zeichenfolge
"Hallo Welt!" nur an einer Stelle gespeichert. Soll nun str1
verändert werden, so wird hinsichtlich der Variable str2
reagiert,
indem eine
Kopie von "Hallo Welt!" erstellt und der interne Referenzzähler (in
den oben genannten MFC-Files findet man ihn als Variable CStringData::nRefs)
um eins erniedrigt wird. Diese Referenzzähler-Methode finden Sie auch
bei COM.
Wir haben nun Zeichenfolgen
erstellt, zugeordnet und auf diese zugegriffen. Man kann Zeichenfolgen
auch auf
einfachste Weise miteinander vergleichen. Hierzu verwendet man die
Operatoren <,
<=,
==,
>=,
> und !=. Als Ergebnis erhält man TRUE oder
FALSE
zurück. Nachstehend finden Sie einen solchen Größenvergleich:
#include
<afx.h> #include <iostream> using namespace std; CString maxString( CString& A, CString& B ) { if (A >= B) return A; // hier erfolgt der Vergleich else return B; } CString minString( CString& A, CString& B ) { if (A <= B) return A; // hier erfolgt der Vergleich else return B; } int main() { char szString1[255]; // char-Array-String char szString2[255]; // char-Array-String cout << "Geben Sie bitte die erste Zeichenfolge ein: "; cin.getline( szString1, 255 ); cout << "Geben Sie bitte die zweite Zeichenfolge ein: "; cin.getline( szString2, 255 ); CString str1 = _T(szString1); CString str2 = _T(szString2); cout << "Der String \"" << LPCTSTR ( maxString( str1, str2 ) ) << "\" folgt nach dem String \"" << LPCTSTR ( minString( str1, str2 ) ) << "\"" << endl; while (cin.get() != '\n'); } |
In vorstehendem Beispiel sieht man auch den Einsatz selbst geschriebener Funktionen namens minString(...) und maxString(...), die Referenzen auf CString als Parameter übernehmen und die 'kleinere' oder 'größere' CString-Variable zurückgeben.
Das Vergleichen zweier Strings auf Gleichheit erfolgt mit den Funktionen
int Compare( LPCTSTR lpsz )Eine hilfreiche Funktion ist CString::Format(...). Die String-Ausgabe wird analog der Funktion sprintf(...), die der Programmiersprache C entstammt, formatiert. Sie sehen an diesem Beispiel, wie die MFC noch auf typische Eigenschaften der Sprache C zurückgreift. Solche historisch gewachsenen Implementierungen findet man in der Windows-Programmierung mit der Sprache C++ immer wieder.
#include
<afxwin.h> #include <iostream> using namespace std; int main() { int z[10]; for(int i=0; i<10; ++i) {z[i] = i+1;} CString Ausgabe; CString Hilfsstring( _T("Die ersten natuerlichen Zahlen sind:") ); Ausgabe.Format( "%s %d %d %d %d %d %d %d %d %d %d.\n", Hilfsstring, z[0],z[1],z[2],z[3],z[4],z[5],z[6],z[7],z[8],z[9] ); cout << LPCTSTR(Ausgabe) << endl; AfxMessageBox( Ausgabe, MB_OK | MB_ICONINFORMATION ); return 0; } |
Die MFC-Klasse CString bietet auch gut geeignete Funktionen zum Durchsuchen von Zeichenfolgen nach anderen Zeichenfolgen. Man hat die Funktionen
int Find( TCHAR ch )Wir schauen uns zur
Veranschaulichung ein kleines Beispiel an:
#include
<afx.h> #include <iostream> using namespace std; int main() { CString Glocke = "Fest gemauert in der Erden Steht die Form, aus Lehm gebrannt. Heute muß die Glocke werden."; cout << Glocke.Find( "Erden" ) << endl; // Resultat: 21 cout << Glocke.Find( "Erden", 10 ) << endl; // Resultat: 21 cout << Glocke.Find( "Erden", 25 ) << endl; // Resultat: -1 cout << Glocke.Find( 'E' ) << endl; // Resultat: 21 CString S = "E"; const char *pS = LPCTSTR( S ); cout << Glocke.Find( pS, 0 ) << endl; // Resultat: 21 cout << Glocke.Find( 'G' ) << endl; // Resultat: 76 cout << Glocke.ReverseFind( 'G' ) << endl; // Resultat: 76 cout << Glocke.Find( '.' ) << endl; // Resultat: 60 cout << Glocke.ReverseFind( '.' ) << endl; // Resultat: 89 cout << Glocke.FindOneOf("EG") << endl; // Resultat: 21 cout << Glocke.FindOneOf("GE") << endl; // Resultat: 21 cout << Glocke.FindOneOf("ß") << endl; // Resultat: 70 return 0; } |