[c++] "undefined reference to" abstracte constructor

Pagina: 1
Acties:

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 28-08 12:00

Janoz

Moderator Devschuur®

!litemod

Topicstarter
In mijn c++ project heb ik nu een 'abstracte' class (ben vooral bekend met Java, dus zal waarschijnlijk ook veel javatermen gebruiken :) ). Vervolgens heb ik een implementatie die deze class extend. Ik zal hieronder even de beide header files plaatsten:

MTAttribute.h
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifndef MTAttribute_h
#define MTAttribute_h
#include <iostream>
class MTAttribute {
public:
  MTAttribute();
  MTAttribute(const MTAttribute& mta);
  virtual ~MTAttribute() = 0;
  MTAttribute(unsigned long x, unsigned long y, unsigned long z);

  virtual MTAttribute * getNewInstance() =0;
  virtual void addData(unsigned long x, unsigned long y, unsigned long z) = 0;
  virtual void mergeAttribute(const MTAttribute& mta) = 0;
  virtual double getAttribute() = 0;
private:
};
#endif /* MTAttribute_h */

InertiaAttribute.h
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef InertiaAttribute_h
#define InertiaAttribute_h
#include "MTAttribute.h"

class InertiaAttribute : public MTAttribute {

public:
  InertiaAttribute();
  InertiaAttribute(const InertiaAttribute& mta);
  ~InertiaAttribute();
  InertiaAttribute(unsigned long x, unsigned long y, unsigned long z);

  MTAttribute * getNewInstance();
  void addData(unsigned long x, unsigned long y, unsigned long z);
  void mergeAttribute(const MTAttribute& mta);
  double getAttribute();
private:
};
#endif /* InertiaAttribute_h */


Als ik dit vervolgens ga compileren is er niks aan de hand todat de verschillende .o files moeten worden gelinked. Ik krijg dan de volgende melding:

wingtip54 : ~/afprog/5 > make
g++ test.o MaxTree3d.o ShortVolume.o MTAttribute.o InertiaAttribute.o -o "filter.exe" -lglut -lGLU -lGL -lpthread -L/usr/X11R6/lib -lXi -lXmu -lXext -lXt -lX11 -O6 -march=i686 -fexpensive-optimizations -funroll-loops -Wall
InertiaAttribute.o: In function `InertiaAttribute::getNewInstance(void)':
InertiaAttribute.o(.text+0x7c): undefined reference to `MTAttribute::~MTAttribute(void)'
InertiaAttribute.o: In function `InertiaAttribute::InertiaAttribute(void)':
InertiaAttribute.o(.text+0x11b): undefined reference to `MTAttribute::~MTAttribute(void)'
InertiaAttribute.o: In function `InertiaAttribute::InertiaAttribute(InertiaAttribute const &)':
InertiaAttribute.o(.text+0x18b): undefined reference to `MTAttribute::~MTAttribute(void)'
InertiaAttribute.o: In function `InertiaAttribute::~InertiaAttribute(void)':
InertiaAttribute.o(.text+0x1e3): undefined reference to `MTAttribute::~MTAttribute(void)'
InertiaAttribute.o: In function `InertiaAttribute::InertiaAttribute(unsigned long, unsigned long, unsigned long)':
InertiaAttribute.o(.text+0x247): undefined reference to `MTAttribute::~MTAttribute(void)'
collect2: ld returned 1 exit status
make: *** [filter.exe] Error 1

Ik ben zo langzamerhand een beetje ten einde raad. Zoals is te zien geeft ie bij alle constructoren van de subclass aan dat hij de constructor van de abstracte class niet kan vinden. Ook bij getNewInstance geeft hij deze melding, maar dat zal waartschijnlijk komen omdat ik daar een nieuwe instantie van de class aanmaak en hierin dus ook de constructor wordt aangeroepen. Waarschijnlijk ligt het probleem ergens in de makefile, maar dat weet ik absoluut niet zeker.

Ik maak geen gebruik van een IDE omdat deze hier niet aanwezig is. De makefile heb ik dus met de hand moeten maken mbv enkele voorbeelden. Is er iemand die weet waar dit door zou kunnen komen en hoe ik het op kan lossen?

Als er eventueel meer info nodig is (makefile, beide cpp bestanden), vraag maar, dan zet ik het er ook wel ff bij.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 02:09
Ten eerste is het reference. Lees de FAQ/QuickStart; goed spellen is echt niet zo moeilijk, zeker niet als je 't over typt (of copy-paste). Een mod moet natuurlijk helemaal het goede voorbeeld geven.

Verder krijg je meldingen over destructoren (GEEN constructoren!).

Dan natuurlijk de vraag: implementeer je die destructor (die in je base class als pure virtual gedeclareerd wordt) wel?

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 28-08 12:00

Janoz

Moderator Devschuur®

!litemod

Topicstarter
Staat toch reference :Z :) ..

Maar om ff op je vraag terug te komen. Ja, het zijn idd references naar destructoren (ik zit er blijkbaar al zo lang naar te gapen dat ik het ~-tje helemaal over het hoofd zie. Maar de destructor in InertiaAttribute is wel geimplementeerd. Maar waarom zouden deze functies de destructor aanroepen trouwens?

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Je begrijpt niet hoe virtuele destructors worden aangeroepen. Bij virtuele destructors wordt eerst de derived destructor aangeroepen en daarna de destructor van de baseclass. Aangezien de baseclass-destructor abstract is, probeert de compiler dus een abstracte methode aan te roepen, en dat gaat niet. Maak een lege destructor in je baseclass en je probleem is opgelost.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 02:09
Verwijderd schreef op 02 september 2002 @ 16:25:
Je begrijpt niet hoe virtuele destructors worden aangeroepen. Bij virtuele destructors wordt eerst de derived destructor aangeroepen en daarna de destructor van de baseclass. Aangezien de baseclass-destructor abstract is, probeert de compiler dus een abstracte methode aan te roepen, en dat gaat niet. Maak een lege destructor in je baseclass en je probleem is opgelost.
Dat ging ik zeggen, maar ik kreeg telefoon. :)

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 28-08 12:00

Janoz

Moderator Devschuur®

!litemod

Topicstarter
Verwijderd schreef op 02 september 2002 @ 16:25:
Je begrijpt niet hoe virtuele destructors worden aangeroepen. Bij virtuele destructors wordt eerst de derived destructor aangeroepen en daarna de destructor van de baseclass. Aangezien de baseclass-destructor abstract is, probeert de compiler dus een abstracte methode aan te roepen, en dat gaat niet. Maak een lege destructor in je baseclass en je probleem is opgelost.


Dan compileerd ie wel, maar krijg ik de volgende warning

MTAttribute.h:19: warning: `class MTAttribute' has virtual functions but non-virtual destructor

Het laat me wel een beetje met een onbevredigd gevoel achter. In principe moet die MTAttribute een volledige virtual class zijn die niet zou moeten worden aangemaakt. De verschillende subclasses hebben ook geen data gemeen dus hoeft er ook niks vrijgegeven te worden. In mijn C++ boek (Het C++ boek ISO/ANSI versie) staat dat je je destructor gewoon virtual kunt laten, maar dit blijkt dus niet zo te zijn?


[toevoeging]

Owh, ik krijg ook de volgende melding:

InertiaAttribute.h:20: warning: `class InertiaAttribute' has virtual functions but non-virtual destructor

(regel 20 is de }; afsluiting van de class defenitie) Dit vind ik eigenlijk best vreemd aangezien ik alle methoden die in MTAttribute zitten heb geimplementeerd en in InertiaAttribute geen nieuwe virtual methoden introduceer..

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Je kunt (moet in dit geval) hem wel virtual maken, maar hij moet geimplementeerd zijn:
code:
1
virtual ~MTAttribute() {}

Door de destructor te inlinen kost het ook nog eens geen overhead.

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 28-08 12:00

Janoz

Moderator Devschuur®

!litemod

Topicstarter
big thnx.. dat hielp (de {} ). Nu kan ik eindelijk weer verder met het echte werk :)

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Om nog eens te verduidelijken waarom een virtual destructor geimplementeerd moet zijn in de baseclass:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>

class Base {
public:
    virtual ~Base() { std::cout << "Destroyed Base." << std::endl; }
};

class Derived : public Base {
public:
    virtual ~Derived() { std::cout << "Destroyed Derived." << std::endl; }

};

int main() {
    Derived d;
    return 0;
}

Output:

code:
1
2
Destroyed Derived.
Destroyed Base.

Je ziet dus dat de (virtual) baseclass destructor impliciet ook wordt aangeroepen, en wel na de derived destructor.

  • Ericston
  • Registratie: Maart 2001
  • Laatst online: 05-08 18:36
virtual MTAttribute() = 0;

edit:

dom gokje, sorry als het nergens op slaat + wtf, volgende keer refreshen voor ik reageer

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
virtual ~MTAttribute() = 0; betekent niet dat er geen dtor is. De betekenis is dat de derived class een dtor moet leveren. Deze derived dtor roept vervolgens wel MTAttribute::~MTAttribute() aan. Je moet dus vervolgens MTAttribute::~MTAttribute() { } schrijven, anders is de (impliciete) call waar mietje het over heeft fout. Met de regel virtual ~MTAttribute() = 0; zelf is dus niks mis.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Nog iets... een dtor *moet* gedefinieerd zijn. Maar een functie declaratie mag niet EN puur virtueel zijn (=0) EN een functie definitie specificieren. Dus je kan niet dit doen:

class A {
public:
virtual ~A() = 0 {}
};

Maar je moet je dtor wel definieren (ook al is hij puur virtueel) dus dat wordt dan A::~A() {} buiten je class.

In principe zegt het trouwens niks, een pure virtuele dtor. Dus je kan die =0 net zo goed weg laten. De enige keer dat je het gebruikt is als je een class pure virtual wilt maken, en de enige functie waar het bij kan is de dtor (je hebt alleen een ctor/dtor in je class)

En nog een opmerking, iha maak je bij een pure virtual class de constructor protected, een public ctor slaat namelijk nergens op aangezien je de class toch niet mag instantieren.
Pagina: 1