PDA

Prikaži potpunu verziju : C++ i custom string


Fantastic
15.5.2011, 9:39
Dugo ni ja nisam postavljao pitanja ovde pa ajd malo :) .

Pokusavam da napravim custom string klasu u c++ koja ce naslediti normani std::string

ali imam problem :(

kada pokusam kompajlirati dobijem

main.cpp: In function 'int main()':
main.cpp:8: error: conversion from 'const char [6]' to non-scalar type 'Stefy::String' requested
ovo je main.cpp

#include "/usr/include/sct/stefy_string.h"
#include <iostream>

using namespace std;
int main() {
Stefy::String s;
cin >> s;
Stefy::String t = "stefy";
if (s.contains(t))
cout << "EXTRA\n";
return 0;
}



sct/stefy_string.h


#ifndef STEFY_STRING_H
#define STEFY_STRING_H

//#include <string>
#include "stefy_stdlib.h"

//namespace Stefy {
STEFY_NAMESPACE_BEGIN
class String : public std::string
{

public:
bool starts_with(std::string w);
bool ends_with(std::string w);
int diff(Stefy::String other);
int diff(const std::string& other);
bool contains(Stefy::String t);
//bool contains(std::string t);
};
//}
STEFY_NAMESPACE_END


#endif //STEFY_STRING_H



i sct/stefy_string.cpp


#include "stefy_string.h"

bool Stefy::String::starts_with(std::string w)
{
return substr(0, w.size()) == w;
}

bool Stefy::String::ends_with(std::string w)
{
return substr(size() - w.size(), w.size()) == w;
}

int Stefy::String::diff(Stefy::String other)
{
Stefy::String c = other;
int min_size = 0;
int max_size = 0;
if (size() < c.size()) {
min_size = size();
max_size = c.size();
}
else {
min_size = c.size();
max_size = size();
}

int e = max_size - min_size;

for (int i = 0; i<min_size; i++)
{
if (at(i) != c.at(i))
e++;
}
return e;
}


/*int Stefy::String::diff(const std::string& other)
{
Stefy::String c = other;
int min_size = 0;
int max_size = 0;
if (size() < c.size()) {
min_size = size();
max_size = c.size();
}
else {
min_size = c.size();
max_size = size();
}

int e = max_size - min_size;

for (int i = 0; i<min_size; i++)
{
if (at(i) != c.at(i))
e++;
}
return e;
}*/

bool Stefy::String::contains(Stefy::String t)
{
std::string o = t.c_str();
int s = o.size();

for (int i = 0; i + s <= size(); i++)
{
if (substr(i, s) == o)
{
return true;
}
}

return false;
}


/*bool Stefy::String::contains(std::string t)
{
int s = t.size();

for (int i = 0; i + s <= size(); i++)
{
if (substr(i, s) == t)
{
return true;
}
}

return false;
}*/



u cemu je problem ????

M.Silenus
15.5.2011, 10:29
Probaj da dodaš metode i konstruktore:


Stefy::String(const Stefy::String&);
Stefy::String(const std::string&);
Stefy::String(const char*);

Stefy::String& Stefy::String::operator= (const Stefy::String&);
Stefy::String& Stefy::String::operator= (const std::string&);
Stefy::String& Stefy::String::operator= (const char*);


Štos je što je operator= skriven (pristupaš mu uz pomoć std::string:: operator=). Tj, implementacija bi izgledala ovako nešto


Stefy::String(const Stefy::String& s)
: std::string(s) {}

Stefy::String(const std::string& s)
: std::string(s) {}

Stefy::String(const char* s)
: std::string(s) {}

Stefy::String& Stefy::String::operator= (const Stefy::String& c)
{
std::string::operator= (c);
return *this;
}

Stefy::String& Stefy::String::operator= (const std::string& c)
{
std::string::operator= (c);
return *this;
}

Stefy::String& Stefy::String::operator= (const char* c)
{
std::string::operator= (c);
return *this;
}

Belphegor
15.5.2011, 14:46
Kao sto rece Silenus, std::string ti dodje nesto kao kontenjer pa je zato neophodno da implementiras odgovarajuce konstruktore i operatore. E sad, IMHO kad si vec krenuo rutom da "nasledjujes" od te klase mogao si da to uradis od same "definicije" string-a, posto moze da se desi u buducnosti da pravis svoj alokator (ako ti je brzina imperativ):

class SpecificAllocator;// moze isto da bude template

template < typename MyAllocator >
class MyString : public std::basic_string< char, std::char_traits< char >, MyAllocator >
{
...
};

typedef MyString< std::allocator< char > > DString;// sa "default" alokatorom
typedef MyString< SpecificAllocator > SString;// sa nekim drugim alokatorom
edit: Sad sam tek primetio, zasto u par funkcija ostavljas da ti parametri budu uvedeni po "vrednosti" i ne-konstante kad ih doticne ne menjaju?
Po nekoj logici, recimo ova mekano moze da bude:

int String::diff(const String& other)
{
String c = other;//???sta ce ti ovo
}

Fantastic
15.5.2011, 19:33
Hvala puno na odgovorima

svakako cu probati ovo

Fantastic
15.5.2011, 22:21
problem resen, konstruktor radi :)

a kakva je razlika kad kazem npr

void print(char c*)
void print(string& c)

znam da su to drugi tipovi ali konkretno u cemu je razlika u ovome * i &

M.Silenus
16.5.2011, 10:36
char* c : ovde je c adresa podatka tipa char (otud pokazivač). Naravno, jedan char obično nije dovoljan da se u njega smesti neka niska, pogotovo ne niska terminirana nulom. Treba nam niz char-ova. U tom slučaju, c sadrži adresu prvog elementa niza, c+1 je adresa drugog, c+2 trećeg itd.

Podatak o dužini niza nije deo samog niza (tj. ne postoji objekat niz sa metodom dužina). U slučaju nizova char-ova, zadnji element se postavlja na 0 ('\0' if you will), čisto da bi znao dokle niz ide.

Prilično je očigledno na kakve probleme ovde možeš da naletiš (recimo, šta ako nemam nulu na kraju stringa).

std::string s : s je objekat koji predstavlja nisku, ima metode kojima možeš da pitaš koliko je niska dugačka, koji element je na mestu tom i tom, etc... što su stvati koje su ti već poznate. Interno, std::string može da koristi niz char-ova terminiranih nulom, ali i ne mora. Konkretna implementacija te ne zanima, zanima te ponašanje.

std::string& s : s je referenca na objekat tipa std::string.

Jedno objašnjenje referenci možeš naći na C++ FAQ Lite - References (http://www.parashift.com/c++-faq-lite/references.html). Ukratko referenca je pokazivač na neki objekat, s tom razlikom što je referenca ponaša kao objekat na koji pokazuje.
Primer:

int a; // a je objekat tipa int

int *pa; // pa je pokazivač na objekat tipa int
pa = &a; // pa pokazuje na a
*pa = 3; // promenljivoj na koju pokazuje pa dodeljujemo vrednost 3
// sam pokazivač je nepromenjen

int& ra = a; // ra je referenca na objekat tipa int, i pokazuje na a
// reference moraju dobiti vrednost pri inicijalizaciji
// ne možeš im promeniti vrednost
ra = 4; // objekat na koji ra pokazuje dobija vrednost 4
// primeti nedostatak zvezde :)


Razmotri swap funkciju.

Prvi pokušaj:

void swap(std::string a, std::string b){
std::string tmp = a;
a = b;
b = tmp;
}

// ...
swap(a,b);


U ovom slučaju a i b nisu izmenili vrednosti jer je swap radi sa kopijama objekata a i b, a ne sa samim objektima a i b.

Drugi pokušaj:

void swap(std::string* a, std::string* b){
std::string tmp = *a;
*a = *b;
*b = tmp;
}

// ...
swap(&a, &b);


Ova varijanta radi, jer smo poslali adrese objekata. Ali, pogledaj sintaksu :kreza:

Treći pokušaj:

void swap(std::string& a, std::string& b){
std::string tmp = a;
a = b;
b = tmp;
}

// ...
swap(a, b);


Isto kao i gore, samo mnogo čistije :dedica: