Blockkonstanten in C++
Eine Konstante kann auch in einem Block definiert werden. Solch eine Konstante wird auch als eine „(zu einem Block) lokale Konstante“ bezeichnet.
constant.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ ::std::cout << 12 << '\n';
int const zwoelf( 12 ); ::std::cout << zwoelf << '\n'; }std::cout12
12
Der Name der Konstante kann verändert werden, ohne daß dies die Funktion des Programmes verändert. Ein irreführender Name, wie in dem folgenden Beispiel, sollte natürlich vermieden werden. Doch für den Computer ist der Name ohne Bedeutung: Er verknüpft nur die verschiedenen Stellen seiner Verwendung.
Bei der Ersetzung eines Namens durch einen anderen, muß dieser überall ersetzt werden, wenn sich die Bedeutung nicht ändern soll.
constant1.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ ::std::cout << 12 << '\n';
int const zehn( 12 ); ::std::cout << zehn << '\n'; }std::cout12
12
Typwandlung bei Initialisierung
Die Festlegung des Wertes der Konstante beim Anlegen wird auch als Initialisierung bezeichnet. Bei der Initialisierung einer Konstanten kann ein Ausdruck verwendet werden, der nicht denselben Typ hat wie die Konstante, wenn C++ für diesen Fall eine Umwandlung vorsieht. Dies ist ähnlich wie beim Aufruf einer Funktion, die ein Argument vom Typ der Konstanten erwartet mit einem Argument vom Typ des zur Initialisierung verwendeten Ausdrucks. Das folgende Programmbeispiel zeigt, wie von solchen Umwandlungen Gebrauch gemacht wird.
conversion.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ double const d( 300 );
int const i( 273.15 );
int const j( true );
bool const b( 1 );
::std::cout << d << ", " << i << ", " << j << ", " << b << '\n'; }std::cout300, 273, 1, 1
Anwendungsbeispiel
Das folgende Programm errechnet aus einem benannten Wert »300«, der eine Temperatur in Kelvin darstellen soll, einen anderen benannten Wert: die entsprechende Celsius-Temperatur.
celsius.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ double const t_kelvin( 300 );
double const versatz( 273.15 );
double const t_celsius( t_kelvin - versatz );
::std::cout << t_celsius << '\n'; }::std::cout26.85
Ausdrücke, die neben Operatoren nur Konstanten und Literale enthalten, können oft bereits während der Übersetzung eines Programmes ausgewertet werden und kosten daher nur wenig Laufzeit.
Bereiche in C++
Die Zuordnung von Bezeichnern zu ihren Werten ist auf den Textbereich (Gültigkeitsbereich, scope ) der Bezeichner eingeschränkt. Dieser ist zunächst durch den Block des Bezeichners gegeben. Dieser Block spielt die Rolle eines Namensraumes.
Eindeutigkeit von Bezeichnern
Die Namen eines Bereiches bilden eine Menge: Das bedeutet, daß jeder Namen nur einmal darin vorkommen kann. Daher ist der folgende Text keine korrekte C++ -Übersetzungseinheit.
block.txt#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ int const c( 1 );
int const c( 2 );
::std::cout << c << '\n'; }Diagnose"block.txt", line 5: error: "c" has already been declared in the current scope
int const c( 2 );
^
"block.txt", line 4: warning: variable "c" was declared but never referenced
{ int const c( 1 );
^
Ende der Bereiche
In dem folgenden Beispielprogramm gilt die Definition des Bezeichners »c« als Wert »1« nur in dem Block, der mit der zweiten öffnenden geschweiften Klammer beginnt und mit der ersten schließenden geschweiften Klammer endet. In dem folgenden Block kann der gleiche Bezeichner erneut definiert werden.
block0.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ { int const c( 1 ); ::std::cout << c; }
{ int const c( 2 ); ::std::cout << c; }
::std::cout << '\n'; }std::cout12
block0a.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ { int const c( 1 ); } ::std::cout << c; ::std::cout << '\n'; }Diagnose"block0a.cpp", line 4: warning: constant "c" was declared but never referenced
{ { int const c( 1 ); } ::std::cout << c; ::std::cout << '\n'; }
^
"block0a.cpp", line 4: error: identifier "c" is undefined
{ { int const c( 1 ); } ::std::cout << c; ::std::cout << '\n'; }
^
1 error detected in the compilation of "block0a.cpp".
Verschachtelte Bereiche
Blöcke können ineinander verschachtelt werden, das heißt: ein Block kann einen anderen Block enthalten.
Der innere Block ist dann wieder ein eigener Namensraum. Er „erbt“ alle Definitionen umgebender Namensräume, kann aber alle geerbten Bezeichner in eigenen Definitionen „überschreiben“ (umdefinieren). (Diese Vererbung von Definitionen wird auch bei Klassen verwendet.) Wenn ein innerer Block einen Bezeichner definiert, dann gilt in dem inneren Block auch die Definition des darin definierten Bezeichners ab der Stelle ihres Auftretens. Endet der innere Block, so enden auch die im inneren Block definierten Zuordnungen der Werte zu den Namen.
block1.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ int const c( 9 );
int const d( 9 );
::std::cout << 0 << c << d;
{ ::std::cout << 1 << c << d; int const c( 8 );
::std::cout << 2 << c << d; }
::std::cout << 3 << c << d << '\n'; }std::cout099199289399
Der Leser kann jetzt vorhersagen, was das folgende Programm ausgibt.
block2.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
int main()
{ int const c( 3 );
{ int const c( 4 );
{ int const c( 5 );
::std::cout << c; }
::std::cout << c; }
::std::cout << c << '\n'; }
Beispiele
Möbelkauf
Wenn Büromöbel von einem Endverbraucher erworben werden, sind im Jahre 2003 noch 16 % Mehrwertsteuer zu zahlen. Es werden zwei Tische für je 420 Euro und eine Lampe für 145 Euro Warenwert erworben und 3 % Rabatt vereinbart. Wieviel Euro sind zu zahlen?
In dem folgenden Programm werden Konstanten verwendet, um die Ausdrücke möglichst verständlich und lesbar zu machen.
Rechnung.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
#include <iomanip> // ::std::setprecision
#include <ios> // ::std::fixed
int main()
{ // ewige Konstanten
double const prozent( 0.01 );
double const euro ( 100. ); // intern wird in Cent gerechnet
{ // aktuelle Konstanten
double const mwst( 16. * prozent );
{ // Warenwerte (Preisliste)
double const tisch( 420 * euro );
double const lampe( 145 * euro );
{ // Dieser Einkauf
double const rabatt( 3. * prozent );
double const warenwert( 2 * tisch + 1 * lampe );
double const netto( warenwert * ( 100 * prozent - rabatt ));
double const brutto( netto * ( 100 * prozent + mwst ));
double const gerundet( static_cast<int>( brutto + 0.5 ));
double const forderung( gerundet );
::std::cout << ::std::fixed << ::std::setprecision( 2 ) <<
"Zu zahlen sind " << forderung / euro << " Euro.\n"; }}}}std::coutZu zahlen sind 1108.32 Euro.
Bitentropie
Das folgende Programm berechnet wieviel Entropie ein Bit hat, dabei erfolgt die Ausgabe in SI-Einheiten.
Die Konstante »J« und die Konstante »K« werden hier praktisch nur als Kommentar eingesetzt, um die Einheiten einer physikalischen Größe angeben zu können.
Man bemerkt an dem folgenden Programm, wie angenehm es ist, daß in C++ zwischen Groß- und Kleinschreibung unterschieden wird, so wie dies ja auch in der deutschen Sprache und bei den physikalischen Namen ist. Daher kann der Bezeichner »K« für die Einheit Kelvin und der Bezeichner »k« für die Boltzmann-Konstante verwendet werden.
Bit.cpp#include <iostream> // ::std::cout
#include <ostream> // <<
#include <iomanip> // ::std::setprecision
#include <ios> // ::std::scientific
#include <cmath> // ::std::log
int main()
{ // SI-Einheiten
double const J( 1. ); // Joule
double const K( 1. ); // Kelvin
{ // physikalische Konstanten (nach CODATA, Stand 1998)
double const k( 1.3806503E-23 * J / K ); // Boltzmann-Konstante
{ // Berechnung der Entropie eines Bits
double const bit( k * ::std::log( 2. ));
{ // Ausgabe
::std::cout << ::std::scientific << ::std::setprecision( 2 ) <<
"bit = " << bit /( J / K )<< " J/K.\n"; }}}}std::coutbit = 9,57e-024 J/K.
Übungsaufgaben
- Übungsfrage
pluseins.cpp
#include <iostream> // ::std::cout
#include <ostream> // << int main()
{ double const a( 1 );
::std::cout << a + 1 << '\n';
// Welchen Wert hat die Konstante "a" hier?
}- Welchen Wert hat die Konstante »a« nach der Ausgabe?
- Übungsaufgabe
- Schreiben Sie in das folgende Programm an die Stelle von »/* ... */« einen Ausdruck, so daß der Wert der Konstanten »inch« die Länge einer Strecke in Zoll angibt, deren Zentimeterlänge durch den Zahlenwert in der Konstanten »cm« angegeben ist. Das Programm sollte also dann einen Wert von ungefähr 0,51 ausgeben. (Wenn man dann jedoch den Wert der Konstanten »cm« verdoppeln würde, dann sollte sich der ausgegebene Wert auch verdoppeln.)
- Die ersten vier Zeilen und die letzte Zeile dürfen nicht verändert werden!
umwandlung.cpp
#include <iostream> // ::std::cout
#include <ostream> // << int main()
{ double const l_cm( 1.29 ); /* Laenge in cm (Zentimeter) */
double const l_inch( /* ... */ );
::std::cout << l_inch << '\n'; /* Laenge in Zoll (ca 0,51 Zoll) */ }- Übungsaufgabe
sinus1.cpp
#include <iostream> // ::std::cout
#include <ostream> // <<
#include <cmath> // ::std::sin, ::std::sqrt, ::std::pow int main()
{ double const x( 1 );
double const y( ::std::sin( x ));
double const z( ::std::sqrt( y ));
double const u( ::std::pow( y, 0.51 ));
::std::cout << z << '\n';
::std::cout << u << '\n'; }std::cout
0.917317
0.915735- Schreiben Sie die Einheit »sinus1.cpp« so um, daß dieselben Werte ausgegeben werden und dieselben Numerale und Funktionen zur Berechnung verwendet werden, aber keine Konstanten mehr in dem Programm vorkommen. Ersetzen Sie zunächst die Konstante »x« überall durch ihre Definition, also durch den Wert »1« und entfernen Sie die Definition der Konstante »x«. Nach diesem Schema können dann alle anderen Definitionen eliminiert werden, bis nur noch die beiden Ausgabeausdrücke übrigbleiben.
- Übungsaufgabe
sinus2.cpp
#include <iostream> // ::std::cout
#include <ostream> // <<
#include <cmath> // ::std::sin, ::std::cos, ::std::log int main()
{ ::std::cout << ::std::sin( 1 + ::std::log( 2.178 ))<< '\n';
::std::cout << ::std::cos( 1 + ::std::log( 2.178 ))<< '\n'; }std::cout
0.978526
-0.206122- Schreiben Sie die Einheit »sinus2.cpp« so um, daß derzeit wiederholt vorkommende gleiche Teilausdrücke nur einmal vorkommen. Definieren Sie diese dazu als Konstante oder Konstanten und verwenden Sie die Konstante oder Konstanten dann an deren Stellen. Verwenden Sie aber die in der Einheit »sinus.cpp« vorkommenden Literale und Operatoren, ohne die Werte von Teilausdrücken dabei auszurechnen. Die Ausgabe des Programmes darf sich dadurch nicht ändern.