2010-10-11 12 views
6

Dobra, próbuję zrobić szybką małą klasę do pracy jako rodzaj tablicy hash. Jeśli uda mi się go uruchomić, powinienem być w stanie to zrobić:operator [] = przeciążenie?

StringHash* hash = new StringHash; 
    hash["test"] = "This is a test"; 
    printf(hash["test"]); 

I powinien wydrukować "To jest test".

Wygląda na to, że mam 2 problemy w tym momencie. Po pierwsze ja to zrobił:

const char* operator[](const char* key) { 
    for(int i = 0; i < hashSize; ++i) { 
    if(strcmp(hkeys[i], key) == 0) {return values[i];} 
    } 
    return NULL; 
} 

Ale gdy próbuję patrzeć wartość kompilator narzeka, że ​​

Błąd: nieprawidłowy rodzaje `StringHash * [const char [5]]” do tablicy indeksu

Po drugie operator [] = nie wydaje się być poprawną składnią tutaj. Jedyną rzeczą, którą mogłem znaleźć był operator [], ale myślę, że to nie zadziała, skoro muszę zakodować procedurę wyszukiwania? (Czy ta składnia nie jest używana do zwracania odwołania do elementu tablicy?)

Czy to, co próbuję tutaj zrobić, jest możliwe? Każda rada doceniona. :)


Wydaje się być zamieszaniem w związku z tym, co próbuję zrobić. Będę pisać mój kod:

http://pastebin.com/5Na1Xvaz


gotowego produktu po wszelką pomoc:

http://pastebin.com/gx4gnYy8

Odpowiedz

2

Najpierw chciałbym zapytać, dlaczego piszesz własną mapę HashMap, gdy dostępnych jest kilka wersji, ale nie standardowych.

Czy Twój magazyn hash-map ma char * pointers lub std :: string? (Może przechowywać znaczniki const char *, jeśli jest po prostu tablicą odnośników do danych przechowywanych w innym miejscu, które nie zmienią jej czasu życia).

Co powinien zrobić operator [], gdy przedmiot nie zostanie znaleziony?

Teraz pozwól mi przyjąć, że odpowiedzi są: - Tak jesteśmy przechowywania const char * wskaźniki i przechowujemy NULL w pustej komórce - Kiedy wykonujemy hash [key] = wartość chcemy klucz skojarzyć z wartość - Jeśli po prostu zrobimy hash [klucz], ale nie piszemy, to nie wstawiamy

Można to zrobić za pomocą magicznego obiektu: kiedy przypiszesz const char * do tego obiektu, wstawia on lub zastępuje haszysz. Możesz również uzyskać niejawną konwersję z obiektu na const char * do odczytu.

Jest to dość skomplikowane i lepiej jest trzymać się zwykłego interfejsu mapy: operator [] zawsze wstawia i używasz innej metody tylko do wyszukiwania.

+0

Hmm ... Chyba rozumiem, co mówisz. Chcesz, żebym napisał klasę z operatorem =(), a następnie mam ten uchwyt dodając wpis do tabeli, tak? Widzę, że działa. Rzecz, której się martwię, nie musiałbym przechowywać wewnętrznej tablicy, która utrzymywałaby instancję tej klasy dla każdego ... Ach, nie czekaj. Mogłem po prostu użyć tych obiektów jako wartości wewnętrznych zamiast const char *, a następnie zwrócić je podczas wyszukiwania. Rozumiem. :) – Khat

+0

Strzelaj. Nie pozwolę mi tego zrobić w ten sposób. Ciągle próbuje zwrócić magiczny przedmiot zamiast cortingu. – Khat

+1

Możesz zdefiniować niejawną konwersję między typem "magicznym" i "const char *". Używanie 'std :: string' jest jednak bardziej niezawodnym rozwiązaniem. –

6

Błąd dlatego hash jest wskaźnik. Przejdź do:

StringHash hash; 
+0

Dobry połów. Dziękuję Ci. To nie daje teraz błędu kompilacji. Początkowy test działa, więc mogę teraz sprawdzić wartości w haszu według ich kluczy. – Khat

3

hash nie jest StringHash przedmiot. Jest to wskaźnik do jednego.

Można to zrobić:

(*hash)["test"] = "This is a test";

Można zadać sobie pytanie, dlaczego trzeba wskaźnik do niego w pierwszej kolejności,

StringHash hash; 
hash["test" = "This is a test"; 

... a nawet jeśli nie , dlaczego nie używałbyś inteligentnego wskaźnika, takiego jak auto_ptr.

#include <memory> 
std::auto_ptr<StringHash> hash(new StringHash); 
(*hash)["test"] = "This is a test"; 
2

Napisz StringHash hash; zamiast rzeczy new. C++ to nie Java. :-)

3

Pozostałe odpowiedzi odnoszą się do pierwszego pytania. Jeśli chodzi o twoją drugą ...

Jeśli zwrócisz referencję, zwrócisz l-wartość. Zawsze możesz przypisać do lwartości.

Tak, to (prawie) naprawdę jest takie proste. Polecam uważnie przeczytać, czy potrzebujesz const w różnych miejscach.

Co Pamiętam, że należy zapewnić const i niebędącą const przeciążenie dla operator[], coś tak:

MyType const &operator[](int index) const; // This is the array access version (no assignment allowed), which should work on const objects 
MyType &operator[](int index);  // This is the array access or assignment version, which is necessarily non-const. 

Zobacz this link aby uzyskać więcej informacji.

2

Pierwszy błąd polega na tym, że zadeklarowany skrót to wskaźnik. Typy wskaźników można już używać z operatorem indeksu. Na przykład wskaźnik [3] jest równoważny * (wskaźnik + 3). Nie możesz zmienić tego zachowania. Wykonaj haszowanie samego obiektu:

StringHash sh; 

Co do operatora [] =, nie ma czegoś takiego. Operator indeksu powinien po prostu zwrócić referencję, aby zadanie mogło działać. Oto prosty przykład, jak miałoby to wyglądać tak:

class Indexable 
{ 
    std::string arr[3]; 
public: 
    std::string & operator[](int index) { 
     return arr[index]; 
    } 
    std::string const& operator[](int index) const { 
     return arr[index]; 
    } 
}; 
2

Pięciu problemy:

  1. hash jest wskaźnikiem do StringHash, trzeba dereference go używać operatorów: (*hash)["test"]
  2. Jeśli chcesz przypisać do elementu, musisz zwrócić odniesienie do typu elementu:

    const char *& operator[] (const char* key);

    // ...

    (*hash)["test"] = "This is a test"; // will compile now

  3. null nie jest to słowo kluczowe w C++. Użyj 0 lub NULL.

  4. operator [] musi przydzielić miejsce dla elementu, jeśli go nie znaleziono. Zwracanie NULL nie jest opcją. W przeciwnym razie próba przypisania do wyniku (*hash)["test"] spowoduje awarię twojego programu.
  5. Użyj std :: map lub std :: tr1 :: unordered_map zamiast pisać własną "szybką" klasę.

I po prostu być palantem: Wiesz, że to nie stolik do haszyszu, prawda?

+0

1. Naprawiono. ty 2. Próbuję przeciążyć przypisanie elementu, ponieważ chcę rozpakować rval. 3. Zauważyłem, że zaraz po tym, jak napisałem. Naprawiony. ty 4. Zobacz 2. 5. Nie chcę. :) Dlaczego nie jest to tabela hash? – Khat

+0

@ddd: To nie jest tablica asocjacyjna, ponieważ nie oblicza wartości mieszania kluczy w celu zaindeksowania w tablicy. Zobacz http://en.wikipedia.org/wiki/Hash_table –

+0

Ah. Rozumiem, co masz na myśli. Zwykły stół to chyba. – Khat

1

Czy można użyć numeru boost::unordered_map<std::string, std::string? Wtedy nie musisz się martwić o samodzielne wdrożenie tego.

Zakładając, że jest to ćwiczenie jakiegoś dla siebie: Być może pochodzić z różnych środowisk, ale w C++ normalny sposób, aby zadeklarować hash będzie:

StringHash hash; 

Dodatkowo Twój operator[] może pracować dla druku ale nie zadziała na zlecenie. Normalnie metody operator[] działają przez zwracanie referencji niestanowiących stałych lub obiektu proxy, do którego można przypisać nowe wartości, a użytkownik nie wykonuje żadnych. Jeśli byłbyś w stanie użyć std :: string, mógłbyś przepisać swoją metodę, aby zwrócić niezawarte odniesienie do pozycji w haśle, które powinno zostać odczytane lub przypisane.

Powiązane problemy