webForumDet fria alternativet

Problem vid läkningen

16 svar · 442 visningar · startad av juventus1

juventus1Medlem sedan dec. 2000399 inlägg
#1

Håller på att skriva en stack som använder en länkad lista i C++. All kod kompilerar men när den skall länkas går något snett. Så här ser det ut:

g++ -o lab2 -Wall -g -pedantic lab2.cpp Node.cpp LinkedList.cpp Stack.cpp

lab2.cpp: In function `int main()':
lab2.cpp:8: warning: unused variable `Stack<int> s'
C:\DOCUME~1\Admin\LOCALS~1\Temp/ccaicaaa.o(.text+0x26): In function `main':
C:/Program Files/Laborationer/objprog/lab2/src/lab2.cpp:8: 
undefined reference to `Stack<int>::Stack()'
make: *** [all] Error 1

Koden i lab2.cpp ser ut så här:

#include "Stack.h"
#include <iostream>

using namespace std;

int main()
{
	Stack<int> s;

	return 0;
}

Vad kan problemet bero på?

PeWMedlem sedan juni 200010 432 inlägg
#2

Hur ser Stack-filerna ut?

juventus1Medlem sedan dec. 2000399 inlägg
#3

Här kommer Stack.h

#ifndef STACK_H
#define STACK_H
#include "LinkedList.h"

template <class T>
class Stack {
	private:
		int stack_size;
        	LinkedList<T> list;
	public:
		Stack();
		void push(T o);
	 	T pop();
		int size();
};
#endif

Stack.cpp

#include "Stack.h"
#include <iostream>

template <class T>
Stack<T>::Stack()
{
	std::cout << "Stack constructor" << std::endl;
}

template <class T>
void Stack<T>::push(T data)
{
	list.addFirst(data);
	stack_size++;
}

template <class T>
T Stack<T>::pop()
{
	if (list.isEmpty())
		std::cerr << "Stack is empty";

	stack_size--;
	return list.getFirst();
}

template <class T>
int Stack<T>::size()
{
	return stack_size;
}
PeWMedlem sedan juni 200010 432 inlägg
#4

Vad händer om du kommentarar bort konstruktorn?

juventus1Medlem sedan dec. 2000399 inlägg
#5

Intressant... Nu får jag istället "undefined reference" på konstruktorn till LinkedList. Den är ju deklarerad i Stack.h. Varför är det bara konstruktorerna som krånglar? Jag måste ha missat något... Någon idé?

PeWMedlem sedan juni 200010 432 inlägg
#6

Varför är det bara konstruktorerna som krånglar?

Har nog med vilken ordning kompilatorn klipper och klistrar in saker att göra. Hade kanske funkat annorlunda med nån mer flagga ( ex: -w?) till g++, med avseende på länkningen.

juventus1Medlem sedan dec. 2000399 inlägg
#7

Har provat att änvända -w men det gör ingen egentlig skillnad. Förstår inte varför det ska vara så svårt att få ihop ett så simpelt program... Jag lägger upp koden också ifall någon orkar titta på den. Den innehåller nog en del fel, slängde bara ihop lite snabbt.

PeWMedlem sedan juni 200010 432 inlägg
#8

Ska kolla din kod lite senare. Senast i morgon :)

juventus1Medlem sedan dec. 2000399 inlägg
#9

Tack :)

PeWMedlem sedan juni 200010 432 inlägg
#10

Okej.

Som sagt så har det med hur kompilatorn klipper och klistrar in kod, att göra. Du kan endera slopa Stack.cpp, LinkedList.cpp och Node.cpp och peta in koden från dessa sist i respektive h-fil. Eller så kan du lägga in ett

#include "XXX.cpp"

innan #endif i respektive (XXX)-header.

XXX motsvarar Stack, LinkedList eller Node - som du kanske förstår ;)

Gör du detta försvinner länkstrulet, men du har lite fler fel att fixa innan progget är funktionsdugligt :)

Det kan hända att det finns bättre sätt att hantera detta med länkningen på, dock.

Btw... du behöver inte ange alla .cpp filerna när du kompilerar (kommandoraden eller i makefile), det blir så automagiskt iom att du kör includes på headerna i din lab2.cpp och att du har ett 'straight forward' beroende.

juventus1Medlem sedan dec. 2000399 inlägg
#11

Men är det inte det jag har gjort, dvs gjort include i varje header-fil på det som behövs (inom #ifndef och #endif)?

PeWMedlem sedan juni 200010 432 inlägg
#12

Nja.. inte riktigt. Här är exempel på hur man kan göra som "workaround" med din fil "Stack.h". Samma med de andra filerna.

Alternativ 1:

#ifndef STACK_H
#define STACK_H
#include "LinkedList.h"

//////////////////////
//  deklarationer:

template <class T>
class Stack {
	private:
		int stack_size;
        LinkedList<T> list;
	public:
		Stack();
	    void push(T o);
	    T pop();
		int size();
};
#endif

///////////////////
// definitioner:

template <class T>
Stack<T>::Stack()
{
	stack_size = 0;
}

template <class T>
void Stack<T>::push(T data)
{
	list.addFirst(data);
	stack_size++;
....
....

Alternativ 2

#ifndef STACK_H
#define STACK_H
#include "LinkedList.h"

/////////////////////
// deklarationer:

template <class T>
class Stack {
	private:
		int stack_size;
        LinkedList<T> list;
	public:
		Stack();
	    void push(T o);
	    T pop();
		int size();
};

///////////////////
// definitioner:

#include "Stack.cpp"

#endif

Det finns säkert fler och kanske bättre alternativ, men det här är vad jag på rak arm kan kasta upp som lösning på ditt länkproblem :)

juventus1Medlem sedan dec. 2000399 inlägg
#13

Nu förstår jag hur du menar. Jag använde alternativ 2 och nu fick jag lite kompileringsfel istället, trevligt ;) Tack så mycket för hjälpen!

PeWMedlem sedan juni 200010 432 inlägg
#14

Lugnt... få se om det dyker upp nån bättre lösning? Annars kan du ju markera frågan som löst :)

juventus1Medlem sedan dec. 2000399 inlägg
#15

Problemet löste sig aldrig riktigt, men jag hann inte undersöka det närmare. Nu testade jag igen med ett enkelt litet program. Koden:

Node.h

#ifndef NODE_H
#define NODE_H

template <class T> class Node {
	private:
		T data;
	public:
		Node(T);
		T getData();
};

#endif

Node.cpp

#include "Node.h"
#include <iostream>
using namespace std;

template <class T> Node<T>::Node(T d)
{
	data = d;
}

template <class T> T Node<T>::getData()
{
	return data;
}

int main()
{
	Node<int> node(5);	
	cout << node.getData() << endl;

	return 0;
}

Det här fungerar bra. Problemet uppstår när man vill använda Node ifrån något annat ställe. T ex:

Test.cpp

#include "Node.h"
#include <iostream>
using namespace std;

int main()
{
	Node<int> node(5);	
	cout << node.getData() << endl;

	return 0;
}

När man försöker kompilera det (g++ -o Test Test.cpp Node.cpp) får man felet: C:\DOCUME~1\Admin\LOCALS~1\Temp/ccsZbaaa.o(.text+0x28):Test.cpp: undefined reference to `Node<int>::Node(int)'
C:\DOCUME~1\Admin\LOCALS~1\Temp/ccsZbaaa.o(.text+0x42):Test.cpp: undefined reference to `Node<int>::getData()'

Vad beror det på?

Sang-draxMedlem sedan juli 2002581 inlägg
#16

Om man vill dela upp en mallbaserad (med template<>) klass i en .h och en .cpp-fil måste man använda det reserverade ordet 'export'.

foo.h:

export template<typename T> int foo();

foo.cpp:

template<typename T>
int foo()
{
  return sizeof T;
}

så kommer det att fungera.

Dessvärre stödjer nästan inga kompilatorer detta idag (jag vet bara en och det är ej den du använder) så du får snällt låta bli att dela upp dina mallbaserade funktioner i två filer.

juventus1Medlem sedan dec. 2000399 inlägg
#17

Då förstår jag varför det blev sådana problem så fort man gjorde en mall av det. Tack!

137 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
135 ms — hämta tråd, inlägg och bilagor (db)