Skocz do zawartości

Zarchiwizowany

Ten temat jest archiwizowany i nie można dodawać nowych odpowiedzi.

dmn

[C++] niezdefiniowana referencja do ostream, wzorce

Polecane posty

Wybaczcie że używam forum jako debuggera, ale nie mam pomysłu - tym bardziej że dopiero przykład z książki miał pokazać mi 'na  gruncie' użycie operatora wstawiania << działającego jako funkcja wzorca;

czyżby kolejny niepoprawiony błąd w "C++ dla każdego"? :cool:

Oto listing (19.4) z tej knigi zatytułowany 'uzycie operatora ostream'

#include <iostream>
            using namespace std;
            const int DefaultSize = 10;
          
             class Animal // typ stworzony by w tablicy można było umieszczać obiekty zdefiniowane rowniez przez uzytkownika
            {
                public:
                    //konstr.
                    Animal(int);
                    Animal();
                    ~Animal(){}
                    //akcesory/metody
                    int GetWeight() const { return itsWeight; }
                    void Display() const { cout << itsWeight; }
                private:
                    //sk?adowe
                    int itsWeight;
            };
          
            Animal::Animal(int weight):
            itsWeight(weight)
            {}
          
            Animal::Animal():
            itsWeight(0)
            {}
          
            template <class T> //deklaracja wzorca
            class Array //klasa parametryzowana
            {
                public:
                    //konstruktory:
                    Array(int itsSize = DefaultSize);
                    Array(const Array &rhs);
                    ~Array() { delete [] pType; }
                    //operatory:
                    Array& operator=(const Array&);
                    T& operator[](int offset) { return pType[offset]; }
                    const T& operator[](int offset) const { return pType[offset]; }
                    //akcesory:
                    int GetSize() const { return itsSize; }
          
                      friend ostream& operator<<(ostream&, Array<T>&); //deklaracja zaprzyjaźnionego operatora wstawiania; to tu albo w implementacji prawdopodobnie coś jest nie tak
          
                private:
                    int itsSize;
                    T *pType;
            };
          
            //*******IMPLEMENTACJE**********
          
            //operator<<
            template <class T>
             ostream& operator<<(ostream& output, Array<T>& theArray) //...ale zarówno zwracana jak i otrzymywana jako argument referencja wygląda na zdefiniowaną...
            {
                for (int i=0; i<theArray.GetSize(); i++)
                    output << "[" << i << "] " << theArray[i] << endl;
                return output;
            }
          
            //konstruktor
            template <class T>
            Array<T>::Array(int size):
            itsSize(size)
            {
                pType = new T[size];
                for(int i=0; i<size; i++)
                    pType[i] = 0;
            }
          
            //konstr. kopiuj?cy
            template<class T>
            Array<T>::Array(const Array &rhs)
            {
                itsSize = rhs.GetSize();
                pType = new T[itsSize];
                for (int i=0; i<itsSize; i++)
                    pType[i] = rhs[i];
            }
          
            //operator=
            template <class T>
            Array<T>& Array<T>::operator=(const Array &rhs)
            {
                if (this == &rhs)
                    return *this;
                delete [] pType;
                itsSize = rhs.GetSize();
                pType = new T[itsSize];
                for (int i=0; i<itsSize; i++)
                    pType[i] = rhs[i];
                return *this;
            }
          
          
            int main()
            {
                bool Stop = false; // znacznik dla p?tli
                int offset, value;
                Array<int> theArray;
          
                while(!Stop)
                {
                    cout << "Podaj index (0-9) oraz wartosc. (-1 aby zakonczyc): ";
                    cin >> offset >> value;
          
                    if(offset<0)
                        break;
                    if(offset>9)
                    {
                        cout << "***Prosze uzywac wartosci pomiedzy 0 i 9 ***\n";
                        continue;
                    }
                    theArray[offset] = value;
                }
          
                cout << "\nOto cala tablica:\n";
                cout << theArray << endl;
                return 0;
            }

podczas kompilacji Code::blocks mówi:

C:\Documents and Settings\Juzer\Moje dokumenty\c++\listin_19.4\main.cpp|118|undefined reference to `operator<<(std::ostream&, Array<int|

co rozumiem, jako niezdefiniowana referencja, ale jak na moje laickie oko referencja wygląda na pełną

(zaznaczyłem w komentarzach w kodzie)

PS. Visual c++ mówi w tym samym przypadku:

1>main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Array<int> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$Array@H@@@Z) referenced in function _main

1>C:\Documents and Settings\Juzer\Moje dokumenty\c++\listing_x\Debug\listing_x.exe : fatal error LNK1120: 1 unresolved externals

ale to dla mnie jest mniej zrozumiałe...

PS jedyna nieprawidłowość jaką podejrzewam w tym programie to to, że nawet dzialający operator << nie bedzie w stanie obsłużyć obiektu Animal (nie ma do tego instrukcji) ale to inna broszka już, bo autor sam mówi na koncu przykladu, że "możemy uzyskać zamierzony efekt tylko wtedy gdy dla kazdego typu obiektów przechowywanych w tablicy bedzie zdefiniowany operator <<()."

Wybaczcie że troche chaotycznie, ale mam nadzieje że w miare czytelnie :cool:

Link do komentarza
Udostępnij na innych stronach

Twój kod da się nieco streścić

#include <iostream>

using namespace std;

template <class T>
class A
{
    friend ostream & operator << (ostream & out, A<T> & a);
public:
};

template <typename T>
ostream & operator << (ostream & out, A<T> & a)
{
    return out;
}

int main()
{
    A<int> a;

    std::cout << a;

    return 0;
}

Błąd jest dość skomplikowany, generalnie rozwiązania są dwa:

#include <iostream>

using namespace std;

template <class T>
class A
{
    friend ostream & operator << (ostream & out, A<T> & a);
public:
};

ostream & operator << (ostream & out, A<int> & a)
{
    return out;
}

int main()
{
    A<int> a;

    std::cout << a;

    return 0;
}

#include <iostream>

using namespace std;

template <class T>
class A
{
    friend ostream & operator << (ostream & out, A<T> & a)
    {
        return out;
    }
public:
};

int main()
{
    A<int> a;

    std::cout << a;

    return 0;
}

Link do komentarza
Udostępnij na innych stronach

a można zagnieżdżać komende template? chyba nie, bo kompilator sie nie zgadza na takie operacje jak sprawdziłem :tongue:

w książce piszą "wzorce", to sie tak przyzwyczaiłem ;]

EDIT: o , Mormegil napisał posta jak mi telefon przerwał odpowiadanie gusowi ;]

zaraz to sprawdze i dam znać!

Link do komentarza
Udostępnij na innych stronach

Mormegil:

najpierw napisze czy dobrze wszystko interpretuję;

W zasadzie pierwszy sposób różni się od drugiego tym, że w drugim, implementacja operatora << jest wewnątrz klasy.

Aha, jeszcze w pierwszym sposobie dałeś w deklaracji szablon A<T> natomiast w definicji konkretny egzemplarz A<int>.

Teraz powiem co u mnie się dzieje:

jak wpisałem konkretne egzemplarze wzorca w parametrach - czyli theArray<int> - przestał wyświetlać ostrzeżenia, jednak błąd nadal nie zniknął...

natomiast gdy dałem całą implementację wewnątrz klasy tak jak pokazałeś w drugim sposobie (wraz z wpisaniem egzemplarzy wzorca zamiast szablonu w parametrtach)... W końcu przyjął bez błędów! ;-D

czy to oznacza, że Twoj pierwszy sposób też jest zły, czy może moje IDE jest nadgorliwe? :cool:

a jeszcze tak na marginesie: w streszczeniu napisałeś template <typename T>. Czym to się różni od template <class T>?

Link do komentarza
Udostępnij na innych stronach

Od końca:

- template <typename T> nie różni się niczym od template<class T>. Oba słowa kluczowe dają w tej sytuacji ten sam efekt. Ma to jednak znaczenie, kiedy masz zagnieżdżone typy, ale o tym innym razem,

- u mnie oba sposoby działają, może coś poknociłem przy pisaniu posta,

- tak w pierwszej wersji dajemy konkretny typ A<int> w funkcji poza szablonem, tworzy to funkcję, która odpowiada deklaracji przyjaźni. Dzięki temu linker jest w stanie odnaleźć odpowiednią funkcję. Druga wersja polega na zdefiniowaniu operatora w miejscu deklaracji, co rozwiązuje wszystkie problemy, bo kompilator nie ma problemu z ustaleniem typu A<T>.

Link do komentarza
Udostępnij na innych stronach



  • Kto przegląda   0 użytkowników

    • Brak zalogowanych użytkowników przeglądających tę stronę.
×
×
  • Utwórz nowe...