home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1991 / 01 / cppkurs / bug4.cpp < prev    next >
Encoding:
Text File  |  1990-10-04  |  19.2 KB  |  585 lines

  1.  
  2. (( Listings:   Zeilenumfang ))))))))))))))))))
  3.  
  4. ,,&TIMETEST.CPP  42
  5. ,,&TIMECLSS.H    88
  6. ,,&TIMECLSS.CPP  94
  7. ,,&BUG1.CPP      34
  8. ,,&BUG2.CPP      45
  9. ,,&BUG3.CPP      57
  10. ,,&BUG4.CPP      57
  11.  
  12.  
  13. ,,dHöhere Weihen für C-Programmierer
  14. ,,uC++, die Krone der Schöpfung
  15. ,,avon Thole Groeneveld
  16.  
  17. ,,eDie Programmiersprache C++ ist
  18. Anfang der achtziger Jahre bei den
  19. AT&T Laboratorien von Bjarne
  20. Stroustrup entwickelt worden. Sie
  21. stellt eine Weiterentwicklung von C
  22. dar, mit dem Ziel, syntaktische
  23. Ungereimtheiten zu beseitigen sowie
  24. dem Anfänger den Einstieg durch
  25. einfachere Ein- und Ausgabefunktionen
  26. zu erleichtern. Außerdem sollte die
  27. Fehlersuche durch verbesserte
  28. Typenüberprüfung vereinfacht werden.
  29. C++ bietet also nicht nur erweiterte
  30. Funktionen sondern darüber hinaus im
  31. bisher bekannten Sprachumfang die
  32. elegantere Möglichkeit, große
  33. Programm-Projekte zu gestalten.
  34.  
  35. ,,gW,,neiter, schneller, höher. Diese
  36. Schlagworte beziehen sich in
  37. zunehmenden Maße nicht nur auf
  38. Sportliche Leistungen, sondern sind
  39. symptomatisch für die Compiler-
  40. entwicklung der letzten Jahre. C++
  41. bietet jedoch nicht nur mehr, sondern
  42. präsentiert altgewohntes dem Anfänger
  43. wesentlich mundgerechter. Eine
  44. einfachere Ein- und Ausgabe machen
  45. beispielsweise komplizierte Format-
  46. anweisungen gänzlich überflüssig.
  47. Zeichenketten können über sogenannte
  48. "Streams" bequem und geräteunabhängig
  49. zwischen Modulen ausgetauscht und
  50. ausgegeben werden.
  51. C++ ist keine neue Sprache, sondern
  52. versteht sich vielmehr als Obermenge
  53. von C. Im Prinzip läßt sich jedes C
  54. Programm von einem C++ Compiler
  55. übersetzen. Da der C++ Compiler eine
  56. sehr strenge Typenüberprüfung
  57. vornimmt, werden sich die wenigsten C
  58. Programme jedoch ohne "Warnings"
  59. compilieren lassen.
  60.  
  61. ,,zSicherheit durch Prototyping
  62. ,,nDiese genaue Typenüberprüfung
  63. und auch das Autoprototyping sorgen
  64. dafür, daß durch schlampiges
  65. Programmieren entstandene und im
  66. allgemeinen schwer lokalisierbare
  67. Fehler erst gar nicht auftreten.
  68. Autoprototyping bedeutet, daß die
  69. Typen der Übergabe-- und Rückgabe-
  70. parameter vor dem Aufruf der Funktion
  71. bekannt sein müssen.
  72.  
  73. ,,zVon SIMULA zu C++
  74. ,,nC++ ist aber nicht nur ein ver-
  75. bessertes C, sondern beinhaltet in
  76. letzter Konsequenz eine ganz andere
  77. Programmierphilosophie, das objekt-
  78. orientierte Programmieren. Dieses
  79. Konzept wurde erstmals für die 1967 in
  80. Norwegen entwickelte Sprache SIMULA
  81. benutzt, die, wie der Name schon sagt,
  82. hauptsächlich zur Programmierung von
  83. Simulationen verwendet wird. Leider
  84. blieb SIMULA und damit auch die OOP -
  85. Technik lange relativ unbekannt. Das
  86. änderte sich erst durch das Aufkommen
  87. von SMALLTALK in den siebziger Jahren.
  88. Dabei erregte aber weniger die
  89. Programmiersprache als die aufwendig
  90. mit einer Maus bedienbare graphische
  91. Benutzeroberfläche die Aufmerksamkeit
  92. der Öffentlichkeit. Außerdem sind die
  93. meisten SMALLTALK-Systeme so rechen-
  94. und speicherintensiv, daß sie Work-
  95. stations mit einigen MIPS und Mega-
  96. bytes brauchen und damit für die
  97. Mehrheit der einfachen PC-Benutzer
  98. uninteressant bleiben.
  99.  
  100. ,,zHybridsprachen
  101. ,,nWirklich populär wurden objekt-
  102. orientierte Sprachen erst durch die
  103. sogenannten Hybridsprachen. Darunter
  104. versteht man herkömmliche Programmier-
  105. sprachen wie Pascal und C, die um
  106. objektorientierte Sprachelemente
  107. erweitert wurden.
  108. Der große Vorteil liegt darin, daß der
  109. Neuling keine vollkommen neue Sprache
  110. lernen muß und ihm damit der Einstieg
  111. erleichtert wird. Zudem sinkt die
  112. Effizienz, auf die bei der
  113. Implementierung eines C++ Compilers
  114. sehr großen Wert gelegt wird, kaum im
  115. Vergleich zu herkömmlichen Sprachen.
  116. Diese Tatsache wird besonders für
  117. Hersteller von professioneller Soft-
  118. ware wichtig sein und die Entscheidung
  119. für ihren Umstieg auf C++ erleichtern.
  120.  
  121. ,,zWieso, weshalb, warum?
  122. ,,nDoch was ist überhaupt objekt-
  123. orientiertes Programmieren und braucht
  124. man so etwas überhaupt?
  125. Sicherlich macht es keinen Sinn,
  126. kleine übersichtliche Programme durch
  127. den geheimnisvollen Anflug des
  128. gefürchteten Zeitgeistes nun
  129. objektorientiert zu programmieren.
  130. Wirklich effizient ist dieses Konzept
  131. erst bei größeren und unübersicht-
  132. lichen Programmen. Ziel ist es, daß
  133. komplexe Gesamtproblem in einzelne
  134. Einheiten, sogenannte Objekte, auf-
  135. zuspalten. Diese Objekte bearbeiten
  136. dann völlig selbstständig die ihnen
  137. zugeteilte Aufgabe und kommunizieren
  138. mit ihrer Umgebung über eine genau
  139. dokumentierte Schnittstelle.
  140.  
  141. ,,zModularität durch Objekte
  142. ,,nIn einem solchen Objekt sind nicht
  143. nur die Funktionen, sondern auch die
  144. von ihnen manipulierten Daten
  145. zusammengefaßt. Diese Daten stellen so
  146. etwas wie den inneren Status des
  147. Objektes dar. Normalerweise sollte auf
  148. sie nur über den Umweg einer Funktion
  149. zugegriffen werden, um fehlerhafte
  150. Angaben abfangen zu können. C++
  151. erlaubt aber aus Effizienzgründen auch
  152. den direkten Zugriff. Deklariert
  153. werden Objekte in einer sogenannten
  154. Klassendeklaration. Der Programmierer
  155. legt hier die verwendeten Variablen
  156. und ihre Typen fest. Funktionen, die
  157. diese Daten manipulieren sowie deren
  158. Übergabe-- und Rückgabeparametern
  159. werden ebenfalls hier festgelegt.
  160. Daten und Funktionen können außerdem
  161. noch gegen Zugriff von außerhalb
  162. geschützt werden. Gegen brutalen
  163. Pointerzugriff bewahren diese
  164. Mechanismen zwar nicht, doch wer auf
  165. geschützte Objekte direkt zugreift
  166. weiß entweder was er tut oder sollte
  167. die Finger von der objektorientierten
  168. Programmierung lassen.
  169.  
  170. ,,zDie Privatsphäre von Objekten
  171. ,,nAuf Daten und Funktionen, denen das
  172. Schlüsselwort "public" voransteht,
  173. kann von außen zugegriffen werden. Sie
  174. sind die Schnittstelle, durch die sich
  175. das Objekt mit der Außenwelt
  176. unterhält. Alles, was nach dem
  177. Schlüsselwort "private" steht, bleibt
  178. in der Privatsphäre des Objektes, zu
  179. der niemand anders als die Mitglieder
  180. des Objektes Zutritt haben.
  181. Zusätzlich darf eine Klassen-
  182. deklaration Konstruktoren und
  183. Destruktoren enthalten. Konstruktoren
  184. werden zu Beginn der Lebenszeit von
  185. Objekten automatisch aufgerufen. Sie
  186. garantieren eine korrekte
  187. Initialisierung der Objekte.
  188. Destruktoren werden automatisch am
  189. Ende der Lebenszeit, also beim
  190. Verlassen einer Funktion, aufgerufen.
  191.  
  192. ,,zMüllabfuhr im Speicher
  193. ,,nDestructoren beseitigen praktisch
  194. den übrig gebliebenen Speichermüll,
  195. den das Objekt während seiner Lebens-
  196. zeit angesammelt hat. Durch das
  197. freigeben angeforderter System-
  198. resourcen wird so etwas wie eine
  199. halbautomatische Garbage Collection
  200. durchgeführt.
  201. Als einfaches Beispiel für
  202. Konstruktoren, Destruktoren,
  203. öffentliche und private Bereiche habe
  204. ich die Klasse Time geschrieben.
  205. Darüber hinaus zeigt sie die
  206. Möglichkeiten von C++ zur Ein- und
  207. Ausgabe von Objekten, den Gebrauch von
  208. sogenannten statischen Daten und
  209. Funktionen und die Definition von
  210. arithmetischen und vergleichenden
  211. Operatoren.
  212.  
  213. ,,zVon Freunden und Mitgliedern
  214. ,,nObjekte der Klasse Time speichern
  215. Uhrzeiten ab und können diese mit
  216. Hilfe ihrer Member- und Friend-
  217. funktionen manipulieren. Als Daten
  218. besitzt Time drei Integervariablen zur
  219. Speicherung von Stunde, Minute und
  220. Sekunde. Diese Daten sollen gleich zu
  221. Beginn ihrer Lebenszeit mit korrekten
  222. Werten initialisiert werden. Dazu
  223. werden im öffentlichen Teil der Klasse
  224. drei Konstruktorfunktionen mit dem
  225. Klassennamen "Time" deklariert. Sie
  226. unterscheiden sich nur durch ihre
  227. Parameter, die in Klammern bei der
  228. Definition der Variablen im Programm-
  229. text angegeben werden. Für einen C++
  230. Compiler ist es übrigens kein Problem,
  231. zwischen gleichnamigen Funktionen zu
  232. unterscheiden. Lediglich der
  233. Funktionstyp und die Anzahl der
  234. Übergabeparameter müssen
  235. unterschiedlich sein.
  236. Man bezeichnet diese Methode auch als
  237. "Überladen von Funktionen".
  238.  
  239. ,,zFamilienidylle im Speicher
  240. ,,nDie erste der drei beschriebenen
  241. Konstruktorfunktionen hat keine
  242. Parameter, sondern weißt den drei
  243. Variablen Defaultwerte zu. Aus diesem
  244. Grund heißt ein solcher Konstruktor
  245. auch Defaultkonstruktor. Die zweite
  246. Konstruktorfunktion hat drei Parameter
  247. für Stunde, Minute und Sekunde. Dabei
  248. sind die letzten beiden Parameter
  249. optional und können bei der Definition
  250. von Variablen der Klasse Time weg-
  251. gelassen werden. Der Compiler setzt
  252. die in der Funktionsdeklaration
  253. angegebenen Defaultparameter ein. Die
  254. dritte Konstruktorfunktion schließlich
  255. verwendet zur Initialisierung eine
  256. bereits vorhandene Variable von Typ
  257. Time, die der Funktion als Referenz
  258. übergeben wird.
  259.  
  260. ,,zHaben sie Referenzen?
  261. ,,nStroustrup hat den Referenztyp neu
  262. in die Sprachdefinition eingeführt. Er
  263. entspricht in etwa der VAR Deklaration
  264. der Übergabeparameter in einem PASCAL
  265. Programm. Dabei wird der Funktion
  266. nicht die Variable sondern ein
  267. versteckter Zeiger auf sie übergeben.
  268. Durch die Verwendung eines Zeigers
  269. entsteht besonders bei größeren
  270. Objekten ein deutlicher Zeitgewinn.
  271. Allerdings bleiben Manipulationen an
  272. dem übergebenen Objekt auch nach der
  273. Beendigung der Funktion bestehen. Um
  274. diese zu verhindern, wurde bei der
  275. Deklaration der Übergabeparameter das
  276. Schlüsselwort "const" hinzugefügt. Der
  277. Destruktor einer Klasse ist durch eine
  278. Tilde (~) und dem Klassennamen
  279. gekennzeichnet. In unserem Fall hat er
  280. nichts weiter zu tun als einen
  281. lapidaren Kommentar von sich zu geben.
  282. Man könnte ihn auch weglassen, aber
  283. dann hätten wir ja kein Beispiel mehr
  284. für unseren Destructor.
  285.  
  286. ,,zMit der Zeit gehen
  287. ,,nEin Mitglied (Memberfunktion) der
  288. Klasse Time stellt die Funktion
  289. ,,kvoid Time::SetTo (int, int, int)
  290. ,,n dar. Ihre Aufgabe ist es, während
  291. des Programmablaufes die Werte von
  292. Stunde, Minute und Sekunde zu ändern.
  293. Wenn nun beispielsweise "t" ein Objekt
  294. der Klasse Time ist, so würde der
  295. Aufruf ,,kt.SetTo (12,30); ,,n t.hour
  296. auf 12, t.min auf 30 und t.sec auf 0
  297. setzen. Ein direkter Zugriff auf diese
  298. Variablen ist nicht möglich, da sie im
  299. privaten Bereich der Klasse Time
  300. deklariert wurden. Einem alten C Hasen
  301. mag diese Art des Funktionsaufrufes
  302. ein wenig fremd vorkommen.
  303. Verständlicher wird ihm die Sache
  304. vielleicht, wenn man die interne
  305. Interpretation des Ausdrucks offen-
  306. bart. Die Funktionsdeklaration wird
  307. dabei zu ,,kvoid SetTo (Time*
  308. this,int,int,int) ,,n und der
  309. Funktionsaufruf zu ,,kSetTo
  310. (&t,12,30); ,,n
  311.  
  312. ,,zDer this-Operator
  313. ,,nUnserer Funktion wird ein
  314. impliziter Zeiger auf das Objekt als
  315. erstes Argument übergeben. Dieser
  316. Zeiger, auf den der Programmierer
  317. durch das Schlüsselwort "this"
  318. zugreifen kann, ermöglicht die
  319. Manipulation von Daten in statischen
  320. Funktionen wie CheckFlag und
  321. CheckParam. Als Konsequenz daraus
  322. können statische Funktionen keine
  323. Daten verändern, die speziell ein
  324. bestimmtes Objekt betreffen. Ihnen ist
  325. es nur möglich, auf sogenannte
  326. Klassenvariablen zuzugreifen.
  327. Klassenvariablen sind allen Objekte
  328. einer Klasse gemeinsam zugänglich. Die
  329. Klasse Time hat eine Klassenvariable
  330. vom Typ TimeFlag. Sie gibt nach einer
  331. mathematischen Operation zwischen zwei
  332. Objekten an, ob die Operation korrekt
  333. verlaufen ist oder ob es einen Über-
  334. oder Unterlauf gegeben hat. Time::flag
  335. muß extra noch einmal global definiert
  336. (Klassendeklarationen stellen keinen
  337. Speicherplatz bereit!) und
  338. initialisiert werden.
  339.  
  340. ,,zObjektorientierte Parameterprüfung
  341. ,,nCheckParam überprüft nur die ihr
  342. übergebenen Parameter darauf hin, daß
  343. sie in einem zulässigen Bereich
  344. liegen. Dabei bedient es sich keiner
  345. in der Klassendeklaration benutzten
  346. Variablen. ChekParam wurde als
  347. statische Funktion deklariert, da
  348. solche Funktionen wegen des fehlenden
  349. impliziten Arguments schneller sind.
  350. Ein wirklich interessantes Feature ist
  351. die Möglichkeit von C++ zum Überladen
  352. von mathematischen Operatoren.
  353.  
  354. ,,zÜberladen von Operatoren
  355. Time benutzt zwei arithmetische
  356. Operatoren zur Summen- und
  357. Differenzbildung und mehrere
  358. Vergleichsoperatoren. Bei allen diesen
  359. Funktionen, die nichts anderes sind
  360. als selbstdefinierte Operatoren,
  361. handelt es sich um "friend" -
  362. Funktionen. Sie sind kein Bestandteil
  363. der Klasse, haben aber die volle
  364. Zugriffsberechtigung auf den privaten
  365. Teil der ihnen übergebenen Objekte.
  366. Jede mit der Klasse Time befreundete
  367. Operatorfunktion besitzt zwei
  368. Parameter. Der erste bezeichnet das
  369. Objekt, das in einem Ausdruck links
  370. vom Operator steht, während der zweite
  371. für den rechts vom Operator stehenden
  372. Ausdruck gilt.
  373. Den Ausdruck "t3 = t1 + t2;" wandelt
  374. der Compiler also um in "t3 = operator
  375. + (t1, t2);" und ruft die ent-
  376. sprechende Funktion auf.
  377. Selbst der Ausdruck "t3 = 12 - t1;"
  378. wird akzeptiert.
  379.  
  380. ,,zImplizite Typenkonversation
  381. ,,nDies mag zuerst verwundern, ver-
  382. langt doch die Deklaration anstatt der
  383. Zahl "12" den Typ "const Time&". Der
  384. Compiler gibt an dieser Stelle jedoch
  385. nicht auf.
  386. Er versucht vielmehr, einen zu der
  387. Klasse Time gehörigen Konstruktor zu
  388. finden, der eine Integerzahl in ein
  389. Objekt der Klasse Time verwandeln
  390. kann. Da es diesen in der Tat gibt,
  391. wird der Compiler eine solche Code-
  392. zeile ohne zu meckern korrekt
  393. übersetzen. Diese Technik der Typ-
  394. umwandlung nennt sich implizite Typen-
  395. konversion. Etwas verdächtig sieht
  396. auch die Deklaration der Funktion
  397. ,,kConvertToSeconds,,n aus, an deren
  398. Ende das Schlüsselwort "const" steht.
  399. Es sagt aus, daß der Programmcode des
  400. Funktionskörpers keinerlei
  401. Veränderungen an den Daten des Objekts
  402. vornehmen darf. Sein Status bleibt
  403. also konstant. Der tiefere Sinn für
  404. diese Deklaration liegt in dem Aufruf
  405. der Funktion in den Operator-
  406. funktionen. Diese dürfen selbst die
  407. Ihnen übergebenen Objekte der Klasse
  408. Time nicht verändern. Rufen diese
  409. Objekte aber eine ihrer Member-
  410. funktionen auf, so könnten sie ihre
  411. Daten verändern. Aus diesem Grunde
  412. erlaubt der Compiler den Operator-
  413. funktionen nur solche Funktionen
  414. anzuwenden, die den Status der Time-
  415. objekte auf keinen Fall verändern.
  416.  
  417. ,,zErsatz für printf und scanf
  418. ,,nDie Ein- und Ausgabe hat sich in
  419. C++ gründlich geändert und ver-
  420. einfacht. Man ist nicht mehr
  421. ausschließlich auf komplizierte und
  422. fehleranfällige Formatanweisungen
  423. angewiesen. Als Alternative werden die
  424. sogenannten "streams" (=Ströme)
  425. angeboten, die den Datentransport
  426. zwischen den Variablen und den I/O -
  427. Objekten regeln. Fließen die Daten von
  428. einer Variable zu einem I/O - Objekt,
  429. so ist das eine Ausgabe und anders-
  430. herum eine Eingabe. Die in der
  431. Includedatei <iostream.h> definierte
  432. Variable cout ist ein Objekt der
  433. Klasse ostream_withassign und für die
  434. Ausgabe zuständig. Dazu hat die Klasse
  435. ostream_withassign (bzw. ihre
  436. Elternklasse ostream) einige "<<"
  437. Operatoren für die gängigsten Daten-
  438. typen überladen.
  439. Der Compiler sucht sich dann die
  440. passende Operatorfunktion heraus. Das
  441. Interessante an diesen Funktionen ist,
  442. daß beliebig viele auch vom Typ
  443. verschiedene Variablen aneinander
  444. gehängt werden können. Möglich wird
  445. diese Technik durch den Rückgabe-
  446. parameter der Funktionen, der per
  447. Referenz stehts auf cout verweist.
  448. Dabei wird die Funktion, die den
  449. nächsten Datentyp behandelt, als
  450. Ausgabeobjekt weiterverwendet.
  451. Cout wird also praktisch von einer
  452. Funktion zur nächsten weiter gereicht.
  453.  
  454. ,,zVereinfachte Eingabefunktion
  455. ,,nFür die Eingabe gilt im Prinzip das
  456. Obengesagte. Als Operator wird ">>"
  457. statt "<<" verwendert, um die
  458. umgekehrte Richtung des Datenflußes zu
  459. verdeutlichen.
  460. In unserer Beispielklasse Time sind
  461. natürlich auch die I/O - Operatoren
  462. nach dem gleichen Schema überladen.
  463. Damit wird eine wesentlich komfort-
  464. ablere und einheitliche Ein- und
  465. Ausgabe erhalten. Dazu wurden zwei
  466. friend Operatorfunktionen deklariert,
  467. die als ersten Parameter eine Referenz
  468. auf das Ein- bzw. Ausgabeobjekt und
  469. als zweiten eine Referenz auf ein
  470. Objekt vom Typ Time haben. Rückgabe-
  471. parameter ist die Referenz auf den
  472. ersten Eingangsparameter, also das I/O
  473. - Objekt.
  474. Der Ausgabeoperator benutzt die
  475. Streammanipulatorfunktion setw(int),
  476. um die minimale Feldbreite für die
  477. nächste Ausgabe auf zwei zu setzen.
  478. Eventuell auftretende Leerstellen
  479. werden durch eine '0' aufgefüllt. Der
  480. Eingabeoperator liest Stunde, Minute
  481. und Sekunde zunächst in temporäre
  482. Variablen ein. Die istream Member-
  483. funktion get() filtert Trennzeichen
  484. zwischen den einzelnen Eingaben
  485. heraus. Der Aufruf des Konstruktors
  486. Time::Time(int,int,int) sorgt dafür,
  487. daß das einlesende Timeobjekt auf
  488. jeden Fall korrekte (wenn bei fehler-
  489. hafter Eingabe auch nicht die
  490. gewünschten) Werte erhält.
  491.  
  492. ,,zMit Inline-Code gegen Overhead
  493. ,,nUm den Overhead des Funktions-
  494. aufrufes zu verringern, wurden einige
  495. Funktionen als inline definiert. Sie
  496. müssen dann allerdings mit in das
  497. Includefile hinein geschrieben werden.
  498. Der Compiler baut sie dann, solange
  499. sie nicht zu groß werden, wie Makros
  500. aber mit voller Typenüberprüfung in
  501. den Programmtext ein. Der Vorteil der
  502. höheren Geschwindigkeit wird aber
  503. durch den Nachteil des größeren
  504. Programmcodes erkauft. Es liegt also
  505. am Programmierer, Schwerpunkte zu
  506. setzten.
  507. Leider compilierte der Turbo C++
  508. Compiler die Timeklasse nur, wenn bei
  509. den Compileroptionen das "Out-of-line
  510. Inline Functions" Flag gesetzt wird.
  511. In diesem Fall werden alle Inline-
  512. funktionen wie ganz normale Funktionen
  513. aufgerufen, um das Programm leichter
  514. debuggen zu können. Setzt man dieses
  515. Flag nicht, steigt der Compiler beim
  516. Übersetzen der Ausgabeoperatorfunktion
  517. mit einer falschen Fehlermeldung aus.
  518.  
  519. ,,zBugs im Turbo C++
  520. ,,nGrund dafür ist die Stream-
  521. manipulatorfunktion ,,ksetw(int),,n
  522. aus <iomanip.h>. Diese Funktion hat
  523. als Rückgabeargument ein Objekt der
  524. Klasse smanip_int, die den "<<"
  525. Operator mit den Übergabeparametern
  526. ostream& und smanip_int& und dem Rück-
  527. gabeparameter ostream& überladen hat.
  528. Auf diese Weise sollte sich die
  529. Funktion setw(int) schön in die Kette
  530. der Ausgabevariablen einfügen lassen.
  531. Der Ausgabeoperator von smanip_int
  532. gibt keine Zahl aus, sondern bringt
  533. das ihm übergebene Ausgabeobjekt
  534. (cout) dazu, die minimale Feldbreite
  535. auf das Argument von setw zu setzen.
  536. Wie gesagt, das alles passiert nur,
  537. wenn das entsprechende Compilierflag
  538. gesetzt ist.
  539. Grund des Fehlers ist aber nicht die
  540. Klasse smanip_int und auch nicht
  541. ostream(_withassign). Es scheint
  542. vielmehr ein Bug im Compiler zu sein,
  543. der dafür sorgt, daß dieser nicht mit
  544. der Zeilenexpansion zurecht kommt.
  545. Abhilfe kann die Verwendung der
  546. Memberfunktion width(int) schaffen.
  547.  
  548. ,,zProbleme mit Zeilenexpansion
  549. ,,nStatt "os << setw(2) << t.hour <<"
  550. schreibt man dann "os.width(2); os <<
  551. t.hour <<"
  552. Das sieht zwar nicht so elegant aus,
  553. erfüllt aber auch seinen Zweck. Eine
  554. andere Möglichkeit wäre bei der
  555. Übersetzung des Implementationsmoduls
  556. TIMECLSS. CPP auf die Zeilenexpansion
  557. zu verzichten und sie bei der
  558. Compilierung von TIMETEST.CPP wieder
  559. einzuschalten. Die dritte Möglichkeit
  560. besteht darin, mit einer "#pragma
  561. Option -vi-" Direktive die Expansion
  562. kurzfristig für den Ausgabeoperator
  563. von Time auszuschalten und danach
  564. wieder einzuschalten. Leider
  565. unterstütz Turbo C++ im Augenblick
  566. diese #pragma-Option noch nicht.
  567.  
  568. ,,zBorlands Compiler
  569. ,,nZum Turbo C++ bleibt ansonsten noch
  570. zu sagen, daß ich den Compiler für ein
  571. hervorragendes Werkzeug zur objekt-
  572. orientierten Programmierung halte. In
  573. der vorliegenden Form wird er sicher-
  574. lich die Primitivimplementation der
  575. OOPS-Technik von Turbo Pascal (kein
  576. automatischer Aufruf von Konstruktoren
  577. und Destruktoren, keine privaten und
  578. öffentlichen Bereiche, kein Überladen
  579. von Funktionen und Operatoren usw.
  580. usw.) entweder ins Abseits drängen
  581. oder Borland dazu anregen, Turbo
  582. Pascal mit ähnlichen Features aus-
  583. zustatten.
  584. (us)
  585.