error LNK2019

0

Podczas próby kompilacji programu składającego się z 3 plików dostaję błąd:
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 lista<class osoba="osoba"> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$lista@Vosoba@@@@@Z) referenced in function _main

Program przepisany praktycznie słowo w słowo z "Pasji C++", a to już nie pierwszy błąd, ale z innymi sobie poradziłem, a z tym nie mogę.

Pisane w Visual Studio 2012

Pozdrawiam,
Fryderyk

0

Pokaż kod. Jesteś pewien że wszystkie 3 pliki są w projekcie i kompilujesz je i linkujesz w jedną binarkę?

0

Główny plik:

 

#include "stdafx.h"
#include <iostream>
#include <string>
#include "lista.h"
#include "osoba.h"

using namespace std;

int main()
{
	osoba
		matematyk("Brozek"), 
		muzyk("Chopin"), 
		biochemik("Funk"),
		astronom("Kopernik"),
		wynalazca("Szczepaniak");

	lista<osoba> slawni;

	cout << "sizeof(slawni)= " << sizeof(slawni) << endl;

	slawni.wstaw(biochemik);
	cout << slawni;

	slawni.na_poczatek();
	slawni.wstaw(matematyk);
	cout << slawni;

	slawni.za_koniec();
	slawni.wstaw(wynalazca);
	cout << slawni;

	slawni.nty_wezel(1);
	slawni.wstaw(muzyk);
	cout << slawni;

	slawni.za_koniec();
	slawni.wstaw(astronom);
	cout << slawni;

	cout << "Zle wpisany Kopernik, skorygujemy to\n";
	slawni.nty_wezel(4);
	slawni.usun();
	cout << slawni;

	slawni.nty_wezel(3);
	slawni.wstaw(astronom);
	cout << slawni;

	cout << "wskaznik wybranyW jest na: " << slawni.co_na_wybranym();

	return 0;
}


lista.h:

 
#include <iostream>
using namespace std;

template <class typOBJ>
class lista
{
	struct wezel
	{
		typOBJ * wskobj;
		wezel * nastepca;
			
		wezel() : nastepca(NULL), wskobj(NULL)
		{}
	};

		
	wezel * pierwszyW, *ostatniW, *wybranyW;

public:
	lista()
	{
		pierwszyW = wybranyW = ostatniW = NULL;
	}
	~lista();

	void wstaw(typOBJ &obj);
	void usun();
	typOBJ & co_na_wybranym()
	{
		return *(wybranyW->wskobj);
	}

	void na_poczatek()
	{
		wybranyW = pierwszyW;
	}
	void za_koniec()
	{
		wybranyW = NULL;
	}
	wezel *przejdz_na_nastepny()
	{
		return (wybranyW = wybranyW->nastepca);
	}
	void nty_wezel(int n);

	friend 
		ostream & operator<<(std::ostream &s, lista<typOBJ> &x);
private:
	wezel* poprzedni_wezel(wezel *odnosny)
	{
		wezel *goniec;
	
		for(goniec = pierwszyW;goniec->nastepca != odnosny;goniec = goniec->nastepca);
		
		return goniec;
	}

	void daje_na_poczatek(wezel *nowyW);
	void daje_w_srodku(wezel *nowyW);
	void daje_na_koniec(wezel *nowyW);

	void usuwam_pierwszy();
	void usuwam_ostatni();
	void usuwam_ze_srodka();
};

template <class typOBJ>
void lista<typOBJ>::wstaw(typOBJ &obj)
{
	wezel *nowyW = new wezel;
	nowyW->wskobj = &obj;

	if(wybranyW != NULL)
	{
		if(wybranyW == pierwszyW)
			daje_na_poczatek(nowyW);
		else
			daje_w_srodku(nowyW);
	}
	else
		daje_na_koniec(nowyW);
}

template <class typOBJ>
void lista<typOBJ>::daje_na_poczatek(wezel *nowyW)
{
	nowyW->nastepca = wybranyW;
	pierwszyW = nowyW;
	wybranyW = nowyW;
}

template <class typOBJ>
void lista<typOBJ>::daje_w_srodku(wezel *nowyW)
{
	poprzedni_wezel(wybranyW)->nastepca = nowyW;
	nowyW->nastepca = wybranyW;
}

template <class typOBJ>
void lista<typOBJ>::daje_na_koniec(wezel *nowyW)
{
	if(!pierwszyW)
		pierwszyW=nowyW;
	else
		ostatniW->nastepca = nowyW;
	ostatniW = nowyW;
}

template <class typOBJ>
void lista<typOBJ>::usun()
{
	if(!wybranyW) return ;
	if(wybranyW == pierwszyW)
		usuwam_pierwszy();
	else
	{
		if(wybranyW == ostatniW)
			usuwam_ostatni();
		else
			usuwam_ze_srodka();
	}
}

template <class typOBJ>
void lista<typOBJ>::usuwam_pierwszy()
{
	pierwszyW = pierwszyW->nastepca;
	delete wybranyW;
	wybranyW = pierwszyW;
	if(pierwszyW==NULL) ostatniW = NULL;
}

template <class typOBJ>
void lista<typOBJ>::usuwam_ostatni()
{
	wezel * poprzW;
	poprzW = poprzedni_wezel(wybranyW);

	poprzW->nastepca = NULL;
	ostatniW = poprzW;
	delete wybranyW;
	wybranyW = NULL;
}

template <class typOBJ>
void lista<typOBJ>::usuwam_ze_srodka()
{
	wezel *poprzW;
	poprzW = poprzedni_wezel(wybranyW);

	poprzW->nastepca = wybranyW->nastepca;
	delete wybranyW;
	wybranyW = poprzW;
}

//template <class typOBJ>
//wezel* lista<typOBJ>::poprzedni_wezel(wezel *odnosny)
//{
//	wezel *goniec;
//
//	for(goniec = pierwszyW;goniec->nastepca != odnosny;goniec = goniec->nastepca);
//	
//	return goniec;
//}

template <class typOBJ>
lista<typOBJ>::~lista()
{
	for(wybranyW=pierwszyW; wybranyW; )
	{
		wezel *pamietnik;
		pamietnik = wybranyW->nastepca;
		delete wybranyW;
		wybranyW = pamietnik;
	}
}

template <class typOBJ>
void lista<typOBJ>::nty_wezel(int n)
{
	na_poczatek();
	for(int i = 0;i < n; i++)
	{
		przejdz_na_nastepny();
	}
}

template <class typOBJ>
ostream & operator<<(std::ostream &s, lista<typOBJ> &spis)
{
	lista<typOBJ>::wezel *skoczek = spis.pierwszyW;

	for(int i=0;skoczek;i++, skoczek = skoczek->nastepca)
	{
		s << i << ") " << *(skoczek->wskobj) << " ";
	}
	s << endl;

	return s;
}

osoba.h:

 
#include <iostream>
using namespace std;

class osoba
{
	char nazwisko[30];
public:
	osoba(char* n=NULL)
	{strcpy(nazwisko, n); }

	friend
		ostream & operator<<(ostream &s, const osoba &o);
	friend
		ostream & operator<<(ostream &s, const osoba *wsk);
};

ostream& operator<<(ostream &s, const osoba &o)
{
	s<<o.nazwisko;
	return s;
}
ostream& operator<<(ostream &s, const osoba *wsk)
{
	s<<wsk->nazwisko;
	return s;
}

Jestem pewny, że wszystkie pliki są w jednym katalogu.

0

Ale co ma jakis jeden katalog do tego? Musisz zrobić w Visualu projekt i te pliki do niego dodać.

0

user image

Pliki są w jednym projekcie, także to nie jest problem

0

I takie błędy masz kiedy robisz "build project"? Czy moze wciskasz "compile" na jakimś pliku?

0

Taki błąd dostaję jak klikam "build solution", dokładnie taki:

1>------ Build started: Project: Pojemnik, Configuration: Debug Win32 ------
1> Pojemnik.cpp
1>Pojemnik.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 lista<class osoba="osoba"> &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@AAV?$lista@Vosoba@@@@@Z) referenced in function _main
1>c:\users\fryderyk\documents\visual studio 2012\Projects\Pojemnik\Debug\Pojemnik.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

1

Ale to jest źle napisane w ogóle. Pliki *.h nie powinny zawierać implementacji inaczej niż w deklaracjach a ty sobie te szablony tak podzieliłeś.

0

Mógłbyś z przykładem jakimś napisać o co Ci chodzi, bo nie rozumiem.
Jak pisałem w pierwszym poście, przepisałem ten program z "Pasji C++", żeby później móc na nim pracować, więc myślałem, że będzie dobrze, a tu lipa:/

Chodzi o to, że pliki .h muszę rozbić na dwa, jeden .h drugi .cpp i w tym drugim zamieścić definicje funkcji?

1

W zwykłej sytuacji tak, ale wiem że były jakieś problemy z kompilatorami które sobie z tym nie radziły i bezpieczniej kody mieć w plikach *.h ale tam gdzie deklaracje (tzn w "ciele" klasy a nie poza nią)

0

Po przeniesieniu wszystkich funkcji w pliku lista.h do ciała klasy program odpalił.
Dzięki za pomoc.

A jest może jakaś prosta odpowiedź dlaczego te funkcje nie mogą być zdefiniowane poza ciałem klasy?
I czy kiedyś to było dopuszczalne?

1 użytkowników online, w tym zalogowanych: 0, gości: 1