Potrzebuję pomocy ze zrozumieniem tego kodu.Wszelkie komentarze po bokach dodawałem sam i mogą być błędne. Jest to praca domowa polegająca głównie na zrozumieniu działania kodu, a ciężko mi to wychodzi. Pytania pod kodem :)
kod:
#ifndef __RCSTRING_H__
#define __RCSTRING_H__
#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <iostream>
using namespace std;
class rcstring
{
struct rctext;
rctext* data;
public:
class Range {};
class Cref;
rcstring();
rcstring(const char*);
rcstring(const rcstring&);
~rcstring();
rcstring& operator=(const char*);
rcstring& operator=(const rcstring&);
rcstring& operator+=(const rcstring&);
rcstring operator+(const rcstring&) const;
friend ostream& operator<<(ostream&, const rcstring&);
void check(unsigned int i) const;
char read(unsigned int i) const;
void write(unsigned int i, char c);
char operator[](unsigned int i) const;
Cref operator[](unsigned int i);
int atoi();
rcstring toLower();
rcstring Left(int n);
};
/////////////////POCZATEK STRUCT RCTEXT //////////////////
struct rcstring::rctext
{
char* s;
unsigned int size;
unsigned int n;
rctext(unsigned int nsize, const char* p) //konstruktor
{
n = 1;
size = nsize;
s = new char[size + 1];
strncpy(s, p, size); //skopiuje "size" znaków z p do s
s[size] = '\0';
};
~rctext() //destruktor
{
delete[] s;
};
rctext* detach() //funkcja ta odłącza odwołanie
{
if (n == 1)
return this;
rctext* t = new rctext(size, s);
n--;
return t;
};
void assign(unsigned int nsize, const char* p)
{
if (size != nsize)
{
char* ns = new char[nsize + 1];
size = nsize;
strncpy(ns, p, size); //skopiuje "size" znaków z p do ns
delete[] s;
s = ns;
}
else
strncpy(s, p, size);
s[size] = '\0';
}
private:
rctext(const rctext&);
rctext& operator=(const rctext&);
};
////////////////////KONIEC STRUCT RCTEXT ///////////////////////////
////////////////////POCZĄTEK CLASS CREF ////////////////////////////
class rcstring::Cref
{
friend class rcstring;
rcstring& s;
int i;
Cref(rcstring& ss, unsigned int ii)
: s(ss)
, i(ii){};
public:
operator char() const
{
cout << "operator char() const" << endl;
return s.read(i);
}
rcstring::Cref& operator=(char c)
{
cout << "void operator = (char c)" << endl;
s.write(i, c);
return *this;
}
rcstring::Cref& operator=(const Cref& ref)
{
return operator=((char)ref);
}
};
//////////////////KONIEC CLASS CREF ///////////////////////////
//kody wstawiane w miejsca wywołań
inline rcstring::rcstring()
{
data = new rctext(0, "");
}
inline rcstring::rcstring(const rcstring& x)
{
x.data->n++;
data = x.data;
}
inline rcstring::~rcstring() //to ważne
{
if (--data->n == 0)
delete data;
}
rcstring& rcstring::operator=(const rcstring& x)
{
x.data->n++;
if (--data->n == 0)
delete data;
data = x.data;
return *this;
}
rcstring::rcstring(const char* s)
{
data = new rctext(strlen(s), s);
}
rcstring& rcstring::operator=(const char* s)
{
if (data->n == 1)
data->assign(strlen(s), s);
else
{
rctext* t = new rctext(strlen(s), s);
data->n--;
data = t;
};
return *this;
}
ostream& operator<<(ostream& o, const rcstring& s) //wypisanie do konsoli
{
return o << s.data->s;
}
rcstring& rcstring::operator+=(const rcstring& s)
{
unsigned int newsize = data->size + s.data->size;
rctext* newdata = new rctext(newsize, data->s); //do konstr
strcat(newdata->s, s.data->s); //dopisanie na koniec tego co po prawej
if (--data->n == 0)
delete data;
data = newdata;
return *this;
}
rcstring rcstring::operator+(const rcstring& s) const
{
return rcstring(*this) += s;
}
inline void rcstring::check(unsigned int i) const
{
if (data->size <= i) //ilość odwołań musi być większa od i, a jak nie to jest błąd
throw Range();
}
inline char rcstring::read(unsigned int i) const
{
return data->s[i];
}
inline void rcstring::write(unsigned int i, char c)
{
data = data->detach();
data->s[i] = c;
}
char rcstring::operator[](unsigned int i) const
{
cout << "char rcstring::operator[](unsigned int i) const" << endl;
check(i); //check robi: if(data->size<=i) to throw Range()
return data->s[i];
}
rcstring::Cref rcstring::operator[](unsigned int i) // to co wyżej tylko, że to akurat jest używane w programie patrząc na konsole
{
cout << "Cref rcstring::operator[](unsigned int i)" << endl;
check(i);
return Cref(*this, i);
}
//Początek dodawanych Modułów///////////
int rcstring::atoi()
{
return ::atoi(data->s);
}
rcstring rcstring::toLower()
{
int i=0;
rcstring test; //Dodałem tymczasowy rcstring test
test=data->s; // skopiowałem do niego data->s
int size = strlen(test.data->s); // tu już działam na test.data->s
char *c = new char[size];
while(test.data->s[i]) // też na test
{
c[i] = tolower(test.data->s[i]); // też na test
test.data->s[i]=c[i];
i++;
}
return test; //tu chyba źle, bo samego obiektu nie powinienem raczej zwracać.
}
rcstring rcstring::Left(int n)
{
int size = strlen(data->s);
if(n<0 || size <n)
{
throw Range();
}
char *c = new char[size-n];
strncpy(c,data->s+n,size-n);
return c;
}
#endif /* __RCSTRING_H__ */
- Po co jest i co robi klasa Range{}?
Jest to z tego co widzę pusta klasa i jest użyta tylko do
inline void rcstring::check(unsigned int i) const
{
if (data->size <= i) //ilość odwołań musi być większa od i, a jak nie to jest błąd
throw Range();
}
Czyli używamy jej tylko po to żeby działała na jakieś wyjątki?
- Co robi klasa Cref?
Z tym generalnie bym prosił o największą pomoc, bo zadanie jest z tematu zliczania odwołań.
Dziwię się dlaczego jest dwa razy napisany kod do operator=. Przyjmują różne argumenty co prawda ale czy nie będzie to stwarzało konfliktów?
Próbowałem ogarnąć co się dzieje z tymi funkcjami write i read ale nie rozumiem tego w pełni. Gubię się jak dochodzi do tego funkcja detach() i nie wiem jaką rolę ta klasa pełni w tym kodzie
Jakby ktoś miał czas to bardzo proszę o pomoc z rozumieniu.
Dwie takie same funkcje / moduły do operator[]. Jeden z const, drugi bez i jeden z klasy Cref, a drugi z samej rcstring. Podejrzewam, że profesor zada jakieś pytanie odnośnie tego czym się te operator[] różnią. Jest tu coś ciekawego jeszcze poza tym co wymieniłem
- jedno działa w klasie Cref, drugie w rcstring
- jedno ma const czyli dane przyjmowane nie będą mogły być modyfikowane,a w drugim będą mogły
char rcstring::operator[](unsigned int i) const
{
cout << "char rcstring::operator[](unsigned int i) const" << endl;
check(i); //check robi: if(data->size<=i) to throw Range()
return data->s[i];
}
rcstring::Cref rcstring::operator[](unsigned int i) // to co wyżej tylko, że to akurat jest używane w programie patrząc na konsole
{
cout << "Cref rcstring::operator[](unsigned int i)" << endl;
check(i);
return Cref(*this, i);
}
No i chyba z resztą dam sobie radę. Jakby ktoś miał chwilę mi pomóc to bardzo dziękuję. Odwdzięczam się lajkami :)
Ps: Może to za dużo kodu jak na wrzucenie na forum. Wandbox: https://wandbox.org/permlink/m5CUvnsV7PcjYE4S