Wstep do Programowania 2

Transkrypt

Wstep do Programowania 2
Wstep
˛ do Programowania 2
dr Bożena Woźna-Szcześniak
[email protected]
Akademia im. Jana Długosza
Wykład 8
Przykład realizowany na wykładzie
Klasy StringBad i String. Wstepne
˛
pliki załaczone
˛
jako
źródła.
Przykład z ksiażki:
˛
Stephen Prata. Jezyk
˛
C++. Szkoła
programowania. Wydanie V.
StringBad - interfejs
#include <iostream>
#ifndef STRNGBAD_H_
#define STRNGBAD_H_
class StringBad
{
private:
char * str;
// wskaznik ciagu
int len;
// dlugosc ciagu
static int num_strings;
// liczba obiektow
public:
StringBad(const char * s); // konstruktor
StringBad();
// konstruktor domyslny
~StringBad();
// destruktor
// funkcja zaprzyjazniona
friend std::ostream & operator<<(std::ostream & os,
const StringBad & st);
};
#endif
Uwagi do przykładu
Składowa statyczna, np. static int num_strings;,
ma specjalna˛ własność: program tworzy tylko jedna˛ jej
kopie,
˛ niezależnie od tego ile obiektów danej klasy zostało
powołanych do życie.
Wniosek: składowa statyczna jest współdzielona przez
wszytkie obiekty klasy.
Klasa StringBad - implementacja
#include <cstring>
#include "strngbad.h"
using std::cout;
// inicjalizacja statycznej skladowej klasy
int StringBad::num_strings = 0;
// metody klasy
// konstruuje obiekt StringBad na bazie ciagu jezyka C
StringBad::StringBad(const char * s)
{
len = std::strlen(s);
// ustalenie rozmiaru
str = new char[len + 1]; // przydzial odpowiedniej ilosci pamieci
std::strcpy(str, s);
// inicjalizacja wskaxnika
num_strings++;
// uaktualnienie licznika obiektów
cout << num_strings << ": \"" << str
<< "\" - obiekt utworzony.\n"; // komunikat diagnostyczny
}
Uwagi do przykładu
Składowej statycznej nie można inicjalizować wewnatrz
˛
deklaracji klasy, gdyż deklaracja ta zawiera jedynie opis
sposobu alokacji pamieci,
˛ jednak samej alokacji nie
wykonuje.
Alokacja i inicjalizacja pamieci
˛ dokonuje sie˛ w momencie
utworzenia obiektu danej klasy.
Pola statyczne inicjalizowane sa˛ niezależnie za pomoca˛
instrukcji znajdujacej
˛ sie˛ poza deklaracja˛ klasy - powodem
jest fakt, że składowe statyczne nie sa˛ przechowywane
jako cz˛eść obiektu.
Klasa StringBad - implementacja
StringBad::StringBad() // konstruktor domyslny
{
len = 4;
str = new char[4];
std::strcpy(str, "C++"); // ciag domyslny
num_strings++;
cout << num_strings << ": \"" << str
<< "\" - obiekt domyslny utworzony.\n"; // komunikat diagnostyczny
}
StringBad::~StringBad() // niezbedny teraz destruktor
{
cout << "\"" << str << "\" - obiekt usuniety, ";// diagnostyka
--num_strings;
// koniecznosc
cout << "sa jeszcze " << num_strings << ".\n"; // diagnostyka
delete [] str;
// koniecznosc
}
std::ostream & operator<<(std::ostream & os, const StringBad & st)
{
os << st.str;
return os;
}
Klasa StringBad - test dzialania operatorow new i delete
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &);
// obiekt przekazywany przez referencje
void callme2(StringBad);
// obiekt przekazywany przez wartosc
int main() {
using std::endl;
StringBad headline1("Niech zyje bal !");
StringBad headline2("Ferie tuz tuz ...");
StringBad sports("Narciarstwo");
cout << "Z ostatniej chwili: " << headline1 << endl;
cout << "Temat dnia: " << headline2 << endl;
cout << "Wiadomosci sportowe: " << sports << endl;
callme1(headline1);
cout << "Z ostatniej chwili: " << headline1 << endl;
callme2(headline2);
cout << "Temat dnia: " << headline2 << endl;
cout << "Inicjalizacja obiektu ciagu innym obiektem:\n";
StringBad sailor = sports;
cout << "Z kraju: " << sailor << endl;
cout << "Przypisanie obiektu do innego obiektu:\n";
StringBad knot;
knot = headline1;
cout << "Ze swiata: " << knot << endl;
cout << "Koniec main()\n";
return 0;
}
Klasa StringBad - test dzialania operatorow new i delete
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &);
// obiekt przekazywany przez referencje
void callme2(StringBad);
// obiekt przekazywany przez wartosc
int main() {
...
}
void callme1(StringBad & rsb) {
cout << "Obiekt ciagu przekazany przez referencje:\n";
cout << "
\"" << rsb << "\"\n";
}
void callme2(StringBad sb) {
cout << "Obiekt ciagu przekazany przez wartosæ:\n";
cout << "
\"" << sb << "\"\n";
}
Klasa StringBad - test dzialania operatorow new i delete
bws@bws:~/wyklady/WstepDoProg2/wyklad8$ ./a.out
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
Obiekt ciagu przekazany przez referencje:
"Niech zyje bal !"
Z ostatniej chwili: Niech zyje bal !
Obiekt ciagu przekazany przez wartosc:
"Ferie tuz tuz ..."
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 2.
Temat dnia:
Inicjalizacja obiektu ciagu innym obiektem:
Z kraju: Narciarstwo
Przypisanie obiektu do innego obiektu:
3: "C++" - obiekt domyslny utworzony.
Ze swiata: Niech zyje bal !
Koniec main()
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 2.
"Narciarstwo" - obiekt usuniety, sa jeszcze 1.
"" - obiekt usuniety, sa jeszcze 0.
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0000000000ffe050 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x78a96)[0x7f33cc61ca96]
./a.out[0x400e9f]
......
======= Memory map: ========
00602000-00603000 rw-p 00002000 08:07 1574202
Gdzie jest problem ????
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &);
// obiekt przekazywany przez referencje
void callme2(StringBad);
// obiekt przekazywany przez wartosc
int main() {
using std::endl;
StringBad headline1("Niech zyje bal !");
StringBad headline2("Ferie tuz tuz ...");
StringBad sports("Narciarstwo");
cout << "Z ostatniej chwili: " << headline1 << endl;
cout << "Temat dnia: " << headline2 << endl;
cout << "Wiadomosci sportowe: " << sports << endl;
//....
return 0;
}
Wykonanie – problemu brak
ws@bws:~/WstepDoProg2/wyklad8$ ./a.out
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
"Narciarstwo" - obiekt usuniety, sa jeszcze 2.
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 1.
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 0.
bws@bws:~/WstepDoProg2/wyklad8$
Gdzie jest problem ????
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &);
// obiekt przekazywany przez referencje
void callme2(StringBad);
// obiekt przekazywany przez wartosc
int main() {
using std::endl;
StringBad headline1("Niech zyje bal !");
StringBad headline2("Ferie tuz tuz ...");
StringBad sports("Narciarstwo");
cout << "Z ostatniej chwili: " << headline1 << endl;
cout << "Temat dnia: " << headline2 << endl;
cout << "Wiadomosci sportowe: " << sports << endl;
callme1(headline1);
cout << "Z ostatniej chwili: " << headline1 << endl;
//....
return 0;
}
Wykonanie – problemu brak
ws@bws:~/WstepDoProg2/wyklad8$ ./a.out
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
Obiekt ciagu przekazany przez referencje:
"Niech zyje bal !"
Z ostatniej chwili: Niech zyje bal !
"Narciarstwo" - obiekt usuniety, sa jeszcze 2.
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 1.
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 0.
bws@bws:~/WstepDoProg2/wyklad8$
Gdzie jest problem ????
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &);
// obiekt przekazywany przez referencje
void callme2(StringBad);
// obiekt przekazywany przez wartosc
int main() {
using std::endl;
StringBad headline1("Niech zyje bal !");
StringBad headline2("Ferie tuz tuz ...");
StringBad sports("Narciarstwo");
cout << "Z ostatniej chwili: " << headline1 << endl;
cout << "Temat dnia: " << headline2 << endl;
cout << "Wiadomosci sportowe: " << sports << endl;
callme1(headline1);
cout << "Z ostatniej chwili: " << headline1 << endl;
callme2(headline2);
cout << "Temat dnia: " << headline2 << endl
//....
return 0;
}
Wykonanie – problemu nr 1
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
Obiekt ciagu przekazany przez referencje:
"Niech zyje bal !"
Z ostatniej chwili: Niech zyje bal !
Obiekt ciagu przekazany przez wartosc:
"Ferie tuz tuz ..."
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 2.
Temat dnia:
"Narciarstwo" - obiekt usuniety, sa jeszcze 1.
"" - obiekt usuniety, sa jeszcze 0.
"Niech zyje bal !" - obiekt usuniety, sa jeszcze -1.
Problem nr 1
Z jakiegos powodu przekazanie obiektu headline2 w
argumencie funkcji callme2(headline2); powoduje
wywołanie destruktora.
Przekazanie przez wartość powinno zabezpieczać przed
modyfikacja˛ orginału, ale w naszym przypadku tak nie jest !
Skad
˛ powyższe problemy: z automatycznego
definiowania niejwnych funkcji składowych,
których zachowanie nie jest zgodne z założeniami jakie według programisty - powinna spełniać klasa.
Dokładniej: Konstruktor kopiujacy
˛ i Operator
przypisania.
Domyślny konstruktor kopiujacy
˛ nie zadbał o pole statyczne
i wykonał tzw. kopiowanie płytkie.
Domyślny operator przypisania również wykonał
kopiowanie płytkie.
Konstruktor kopiujacy
˛
Postać:
NazwaKlasy (const NazwaKlasy &);
Zadaniem konstruktora kopiujacego
˛
jest kopiowanie
obiektu istniejacego
˛
do obiektu nowo tworzonego.
Konstrukora kopiujacego
˛
używa sie˛ w czasie inicjalizacji,
ale nie używa sie˛ podczas zwykłego przypisania.
Przykłady użycia:
Dane jest: StringBad A(”Niech zyje bal !”);
StringBad
StringBad
StringBad
StringBad
B(A);
B=A;
B=StringBad(A);
*B= new StringBad(A);
Cze˛ ściowe rozwiazanie
˛
problemu
#include <iostream>
#ifndef STRNGBAD_H_
#define STRNGBAD_H_
class StringBad
{
private:
char * str;
// wskaznik ciagu
int len;
// dlugosc ciagu
static int num_strings;
// liczba obiektow
public:
StringBad(const char * s); // konstruktor
StringBad();
// konstruktor domyslny
StringBad(const StringBad &);
// konstruktor kopiujacy
~StringBad();
// destruktor
// funkcja zaprzyjazniona
friend std::ostream & operator<<(std::ostream & os, const StringBad & st);
};
#endif
Cze˛ ściowe rozwiazanie
˛
problemu
...
StringBad::StringBad(const StringBad & st)
{
num_strings++; // aktualizacja skladowej statycznej
len = st.len;
// ta sama dlugosc ciagu
str = new char [len + 1]; // przydzial pamieci
std::strcpy(str, st.str); // skopiowanie ciagu
}
...
Wykonanie – Cze˛ ściowe rozwiazanie
˛
problemu
bws@bws:~/WstepDoProg2/wyklad8$ ./a.out
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
Obiekt ciagu przekazany przez referencje:
"Niech zyje bal !"
Z ostatniej chwili: Niech zyje bal !
Obiekt ciagu przekazany przez wartosc:
"Ferie tuz tuz ..."
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 3.
Temat dnia: Ferie tuz tuz ...
"Narciarstwo" - obiekt usuniety, sa jeszcze 2.
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 1.
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 0.
bws@bws:~/WstepDoProg2/wyklad8$
Konstruktor kopiujacy
˛ pozwala na rozwiazanie kolejnego problemu
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &);
// obiekt przekazywany przez referencje
void callme2(StringBad);
// obiekt przekazywany przez wartosc
int main() {
using std::endl;
StringBad headline1("Niech zyje bal !");
StringBad headline2("Ferie tuz tuz ...");
StringBad sports("Narciarstwo");
cout << "Z ostatniej chwili: " << headline1 << endl;
cout << "Temat dnia: " << headline2 << endl;
cout << "Wiadomosci sportowe: " << sports << endl;
callme1(headline1);
cout << "Z ostatniej chwili: " << headline1 << endl;
callme2(headline2);
cout << "Temat dnia: " << headline2 << endl
cout << "Inicjalizacja obiektu ciagu innym obiektem:\n";
StringBad sailor = sports;
cout << "Z kraju: " << sailor << endl;
//....
return 0;
}
Wszystko OK!
bws@bws:~/WstepDoProg2/wyklad8$ ./a.out
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
Obiekt ciagu przekazany przez referencje:
"Niech zyje bal !"
Z ostatniej chwili: Niech zyje bal !
Obiekt ciagu przekazany przez wartosc:
"Ferie tuz tuz ..."
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 3.
Temat dnia: Ferie tuz tuz ...
Inicjalizacja obiektu ciagu innym obiektem:
Z kraju: Narciarstwo
"Narciarstwo" - obiekt usuniety, sa jeszcze 3.
"Narciarstwo" - obiekt usuniety, sa jeszcze 2.
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 1.
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 0.
bws@bws:~/WstepDoProg2/wyklad8$
Konstruktor kopiujacy
˛ to jednak nie wszystko ...
#include <iostream>
using std::cout;
#include "strngbad.h"
void callme1(StringBad &);
// obiekt przekazywany przez referencje
void callme2(StringBad);
// obiekt przekazywany przez wartosc
int main() {
using std::endl;
StringBad headline1("Niech zyje bal !");
StringBad headline2("Ferie tuz tuz ...");
StringBad sports("Narciarstwo");
cout << "Z ostatniej chwili: " << headline1 << endl;
cout << "Temat dnia: " << headline2 << endl;
cout << "Wiadomosci sportowe: " << sports << endl;
callme1(headline1);
cout << "Z ostatniej chwili: " << headline1 << endl;
callme2(headline2);
cout << "Temat dnia: " << headline2 << endl
cout << "Inicjalizacja obiektu ciagu innym obiektem:\n";
StringBad sailor = sports;
cout << "Z kraju: " << sailor << endl;
cout << "Przypisanie obiektu do innego obiektu:\n";
StringBad knot;
knot = headline1;
cout << "Ze swiata: " << knot << endl;
cout << "Koniec main()\n";
return 0;
}
Gdzie jest problem ?
bws@bws:~/WstepDoProg2/wyklad8$ ./a.out
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
Obiekt ciagu przekazany przez referencje:
"Niech zyje bal !"
Z ostatniej chwili: Niech zyje bal !
Obiekt ciagu przekazany przez wartosc:
"Ferie tuz tuz ..."
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 3.
Temat dnia: Ferie tuz tuz ...
Inicjalizacja obiektu ciagu innym obiektem:
Z kraju: Narciarstwo
Przypisanie obiektu do innego obiektu:
5: "C++" - obiekt domyslny utworzony.
Ze swiata: Niech zyje bal !
Koniec main()
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 4.
"Narciarstwo" - obiekt usuniety, sa jeszcze 3.
"Narciarstwo" - obiekt usuniety, sa jeszcze 2.
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 1.
"" - obiekt usuniety, sa jeszcze 0.
Gdzie jest problem ?
Instrukcja: knot = headline1;
Dlaczego: wywołanie domyślnego operatora przypisania i
zwiazane
˛
z tym Kopiowanie płytkie.
Efekt:
- obiekt usuniety, sa jeszcze 0., czyli
pusty łańcuch zwiazany z obiektem headline2.
Rozwiazanie
˛
Przedefiniować własny operator przypisania.
Pamietaj
˛ może on być tylko przedefionowywany jako
funkcja składowa !
Pamietaj
˛ aby zwracać referencje do obiektu. W przciwnym
wypadku nie bedzie
˛
można wykonywać instrukcji typu:
A=B=C;
StringBad & StringBad::operator=(const StringBad & st)
{
if (this == &st) return *this;
delete [] str;
len = st.len;
str = new char[len + 1];
std::strcpy(str, st.str);
return *this;
}
Potwierdzenie poprawności:
bws@bws:~/mysvn/wyklady/2011-2012/Matematyka/WstepDoProg2/wyklad8$ ./a.out
1: "Niech zyje bal !" - obiekt utworzony.
2: "Ferie tuz tuz ..." - obiekt utworzony.
3: "Narciarstwo" - obiekt utworzony.
Z ostatniej chwili: Niech zyje bal !
Temat dnia: Ferie tuz tuz ...
Wiadomosci sportowe: Narciarstwo
Obiekt ciagu przekazany przez referencje:
"Niech zyje bal !"
Z ostatniej chwili: Niech zyje bal !
Obiekt ciagu przekazany przez wartosc:
"Ferie tuz tuz ..."
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 3.
Temat dnia: Ferie tuz tuz ...
Inicjalizacja obiektu ciagu innym obiektem:
Z kraju: Narciarstwo
Przypisanie obiektu do innego obiektu:
5: "C++" - obiekt domyslny utworzony.
Ze swiata: Niech zyje bal !
Koniec main()
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 4.
"Narciarstwo" - obiekt usuniety, sa jeszcze 3.
"Narciarstwo" - obiekt usuniety, sa jeszcze 2.
"Ferie tuz tuz ..." - obiekt usuniety, sa jeszcze 1.
"Niech zyje bal !" - obiekt usuniety, sa jeszcze 0.
Udoskonalona klasa String - interfejs
#include <iostream>
using namespace std;
#ifndef STRING1_H_
#define STRING1_H_
class String
{
private:
char * str;
// wskaznik ciagu
int len;
// dlugosc ciagu
static int num_strings; // liczba obiektów klasy
static const int CINLIM = 80; // limit dlugosci ciagu na wejsciu
public:
String(const char * s);
// konstruktor
String();
// konstruktor domyslny
String(const String &);
// konstruktor kopiujacy
~String();
// destruktor
int length () const { return len; }
String & operator=(const String &); // metody przeciazajace operatory
String & operator=(const char *);
char & operator[](int i);
const char & operator[](int i) const;
// funkcje zaprzyjaznione przeciazajace operatory
friend bool operator<(const String &st, const String &st2);
friend bool operator>(const String &st1, const String &st2);
friend bool operator==(const String &st, const String &st2);
friend ostream & operator<<(ostream & os, const String & st);
friend istream & operator>>(istream & is, String & st);
static int HowMany(); // metoda statyczna
};
#endif
Udoskonalona klasa String - definicja
#include <cstring>
#include "string1.h"
using std::cin;
using std::cout;
// inicjalizacja statycznej skladowej klasy
int String::num_strings = 0;
// metoda statyczna
int String::HowMany() {
return num_strings;}
String::String(const char * s)
{ // konstruuje obiekt String z ciagu C
len = std::strlen(s);
// ustawienie dlugosci ciagu
str = new char[len + 1]; // przydzial pamieci
std::strcpy(str, s);
// inicjalizacja wskaznika ciagu
num_strings++;
// aktualizacja licznika obiektow
}
Udoskonalona klasa String - definicja
String::String()
// konstruktor domyslny
{
len = 4;
str = new char[1];
str[0] = ’\0’;
// domyslny ciag obiektow klasy
num_strings++;
}
String::String(const String & st)
{
num_strings++; // aktualizacja skladowej statycznej
len = st.len;
// ta sama dlugosc ciagu
str = new char [len + 1];
// przydzial pamieci
std::strcpy(str, st.str);
// skopiowanie ciagu
}
String::~String()
// destruktor (niezbedny)
{
--num_strings;
// koniecznie
delete [] str;
// koniecznie
}
Udoskonalona klasa String - definicja
// przypisywanie obiektu klasy String
//do innego obiektu tej klasy
String & String::operator=(const String & st) {
if (this == &st) return *this;
delete [] str;
len = st.len;
str = new char[len + 1];
std::strcpy(str, st.str);
return *this;
}
// przypisywanie ciagu C do obiektu klasy String
String & String::operator=(const char * s) {
delete [] str;
len = std::strlen(s);
str = new char[len + 1];
std::strcpy(str, s);
return *this;
}
Udoskonalona klasa String - definicja
// pelny dostep do znaków ciagu (dla obiektów zwyklych)
char & String::operator[](int i){ return str[i]; }
// dostep (do odczytu) do znaków ciagu (dla obiektów const)
const char & String::operator[](int i) const {return str[i];}
// zaprzyjaznione funkcje przeciazajace operatory
bool operator<(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) < 0);
}
bool operator>(const String &st1, const String &st2)
{
return st2.str < st1.str;
}
bool operator==(const String &st1, const String &st2)
{
return (std::strcmp(st1.str, st2.str) == 0);
}
Udoskonalona klasa String - definicja
// wyprowadzenie ciagu na wyjscie
ostream & operator<<(ostream & os, const String & st)
{
os << st.str;
return os;
}
// wczytywanie ciagu z wejscia (uproszczone)
istream & operator>>(istream & is, String & st)
{
char temp[String::CINLIM];
is.get(temp, String::CINLIM);
if (is) st = temp;
while (is && is.get() != ’\n’)
continue;
return is;
}

Podobne dokumenty