In bisherigen Beispielen wurde Member Variablen durch Zuweisung im Constructor initialisiert:
// Initialisierung durch assignment in constructor body My3Vector::My3Vector() { // default constructor x = 0.; y = 0.; z = 0.; // set coords to 0. } My3Vector::My3Vector( double c1, double c2, double c3 ) { x = c1; y = c2; z = c3; // take args for coords }
Alternativ direkte Initialisierung mit spezieller Syntax ausserhalb des "Constructor-Bodys":
// Direckte Initialisierung ausserhalb von constructor body My3Vector::My3Vector() : x(0.), y(0.), z(0.) // default constructor { } My3Vector::My3Vector( double c1, double c2, double c3 ) : x(c1), y(c2), z(c3) { } // bei Vererbung einzige Moeglichkeit Basisklassen--Konstruktor zu rufen MyLVector::MyLVector(double c0, double c1, double c2, double c3) : My3Vector(c1, c2, c3), t(c0) // special initialization syntax {}
In ThreeVector Beispiel ziemlich egal wie man es macht,
aber manchmal direkte Initialisierung erforderlich oder vorzuziehen:
Manchmal muss man in einer Member-Funktion explizit auf das Objekt verweisen oder zugreifen können,
// gleiche Namen fuer lokale Variablen und Member-variablen My3Vector::My3Vector( double x, double y, double z ) { this->x = x; // Expliziter Zugriff auf member variable mit this this->y = y; // x alleine ist lokale Variable (Funktionsargument) this->z = z; }
In C++ unterscheidet man den
scope und die
lifetime von Variablen.
scope: Wo ist ein Objekt bekannt ?
#include <iostream> void tscope_1( ); // declaration void tscope_2( ); int glob_a = 42; // define a global variable int main() { double a = 3.14; cout << "glob_a " << glob_a << endl; cout << "main a " << a << endl; tscope_1( ); tscope_2( ); { int a = -999; // override outside definition cout << "main in block: a " << a << endl; } cout << "main a " << a << endl; // what happened to a ? } void tscope_1( ) { cout << "tscope_1 glob_a " << glob_a << endl; // global variable is known } void tscope_2( ) { int glob_a = -1; // override global variable cout << "tscope_2 glob_a " << glob_a << endl; // unless it's overridden }
Beliebig grosse Arrays/Speicherbereiche können auf diese Weise zur Laufzeit angelegt werden.
Oft die einzige sinnvolle Möglichkeit Variablen oder Objekte über Funktionsgrenzen hinaus zu verwenden.
Nach Gebrauch wieder zurückgeben mit
delete [] arr;
delete tv;
Ansonsten
Memory Leaks !
for ( int i=0; i<100000; i++ ) { double *p = new double[200000]; .... } // ohne delete [] p werden hier 20 GB benoetigt ...
Großes Problem bei komplexen C++ Software Projekten !
void tc1( ); void tc2( ); int main() { // demonstrate automatic, static, dynamic for ( int i=0; i<3; i++ ) { tc1(); tc2(); } int * ap1 = new int[10]; // neuer int array mit 10 Elem. ap1[8] = 99; cout << "ap1[8] " << ap1[8] << endl; int * ap2 = new int(10); // Vorsicht, [] vs (); hier 1 int mit Wert 10 cout << "ap2[0] " << ap2[0] << endl; // Loeschen nicht vergessen; delete [] ap1; // Wichtig: bei new ..[] auch delete [] delete ap2; // sonst nur delete // delete muss innerhalb des Blocks erfolgen, sonst pointer weg, // aber nicht der allozierte Speicher !! } void tc1( ) { int count = 0; // automatic counter count ++; cout << "tc1 " << count << endl; } void tc2( ) { static int count = 0; // static counter count ++; cout << "tc2 " << count << endl; }
GDuckeck 2019-08-01