[C++] Cannot instantiate abstract class?

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Mafkees
  • Registratie: Oktober 2003
  • Niet online
Hey allemaal. Ik heb een ontwerp waarbij ik drie classes heb, namelijk Scanner, Scanner3D en Scanner3DLaserScanner. Scanner en Scanner3D zijn abstracte classes, waar Scanner3DLaserScanner een daadwerkelijke implementatie is. Als ik de volgende constructie echter probeer, krijg ik een foutmelding.

C++:
1
Scanner3D scanner = new Scanner3DLaserScanner();


geeft:

code:
1
 C2259: 'Scanner3D' : cannot instantiate abstract class


- Scanner: algemene class, defineert wat elke scanner moet kunnen
- Scanner3D: erft van Scanner, defineert wat 3D scanners extra moeten kunnen
- Scanner3DLaserScanner: erft van Scanner3D en bevat de daadwerkelijke implementatie

Eerst eens even de header files, volgens mij zijn die verder in orde. De methodes die geimplementeerd moeten worden, zijn ook geimplementeerd.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
//////////////////////////////////////////////////////////////////////////////
// Scanner.h

class Scanner
{
protected:
    wxString m_Description;

protected:
    Scanner(wxString description);

public:
    wxString GetDescription() const;
    virtual bool Initialize() const = 0;
    virtual bool Scan() const = 0;
};

//////////////////////////////////////////////////////////////////////////////
// Scanner3D.h

#include "Scanner.h"
#include "ScanMode3D.h"
class Scanner3D : public Scanner
{
protected:
    Scanner3D();

public:
    // Van deze twee weet ik niet zeker of ze wel nodig zijn op deze plek
    virtual bool Initialize() const = 0;
    virtual bool Scan() const = 0;

    virtual void SetMode(ScanMode3D mode) = 0;
};

//////////////////////////////////////////////////////////////////////////////
// Scanner3DLaserScanner.h

#include "Scanner3D.h"
#include "ScanMode3D.h"
class Scanner3DLaserScanner : public Scanner3D
{
public:
    Scanner3DLaserScanner();

    // Scanner implementation
    bool Initialize() const;
    bool Scan() const;

    // 3D scanner implementation
    void SetMode(ScanMode3D mode);
};


En de constructors zien er als volgt uit:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
Scanner::Scanner(wxString description)
{
    m_Description = description;
}

Scanner3D::Scanner3D() : Scanner("3d")
{
}

Scanner3DLaserScanner::Scanner3DLaserScanner() : Scanner3D()
{
}


Uiteindelijk komt mijn probleem dus neer op dat ik geen base class kan gebruiken om het type aan te geven. Het is de bedoeling dat er een soort van controller class is die weet welke scanner er gebruikt moet worden, maar daar wil ik natuurlijk het type 'Scanner3D' voor gebruiken zodat ik niet hoef aan te geven om welke concrete implementatie het gaat, maar dat doet 't om een of andere reden dus niet. Ik stel het erg op prijs dat jullie al tot zo ver gekomen zijn met lezen :P Thanks alvast!

Acties:
  • 0 Henk 'm!

  • jmzeeman
  • Registratie: April 2007
  • Laatst online: 12-09 16:17
Je probleem is eigenlijk heel simpel, als je in C++ new gebruikt maak je een pointer naar een object. Doordat je variabele geen pointer is wordt hij direct aangemaakt wat dus niet kan. Probeer het volgende is:
C++:
1
Scanner3D * scanner = new Scanner3DLaserScanner();

[ Voor 6% gewijzigd door jmzeeman op 19-05-2010 12:11 ]


Acties:
  • 0 Henk 'm!

  • Mafkees
  • Registratie: Oktober 2003
  • Niet online
jmzeeman schreef op woensdag 19 mei 2010 @ 12:09:
Je probleem is eigenlijk heel simpel als je in C++ new gebruikt maak je een pointer naar een object. Doordat je variabele geen pointer is wordt hij direct aangemaakt wat dus niet kan. Probeer hetvolgende is:.
C++:
1
Scanner3D * scanner = new Scanner3DLaserScanner();
|:( |:( |:( |:( |:( |:( |:( |:(

Dank je, ik keek er strak overheen :P kun je ook topics verwijderen als user? dit is best erg :P

[ Voor 5% gewijzigd door Mafkees op 19-05-2010 12:10 ]


Acties:
  • 0 Henk 'm!

  • Steffannnn
  • Registratie: April 2009
  • Niet online
Ach.. zo iets kan (bijna) iedereen overkomen. Je doet tegelijk je nick ook nog een beetje eer aan :P

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Je hoeft je pure virtuals in Scanner3D niet opnieuw te typen, door inheritance zijn deze sowieso aanwezig en pure virtual. Zodra je het woord virtual bij een class method gebruikt is deze virtual vooralle volgende classe en hoeft niet meer vemeld te worden. Echter het is wel aan te raden om virtual te gebruiken omdat het makkelijker te zien is dat de functie virtual is.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • Mafkees
  • Registratie: Oktober 2003
  • Niet online
NC83 schreef op woensdag 19 mei 2010 @ 14:42:
Je hoeft je pure virtuals in Scanner3D niet opnieuw te typen, door inheritance zijn deze sowieso aanwezig en pure virtual. Zodra je het woord virtual bij een class method gebruikt is deze virtual vooralle volgende classe en hoeft niet meer vemeld te worden. Echter het is wel aan te raden om virtual te gebruiken omdat het makkelijker te zien is dat de functie virtual is.
Thanks! Hoe zit dat trouwens met destructors? Als ik een Scanner3DLaserScanner delete, wilde ik namelijk dat de destructors van Scanner3DLaserScanner, Scanner3D en Scanner wordt aangeroepen. Dat heb ik nu opgelost (door te lezen :P) door alle destructors virtual te maken maar wel te implementeren. Dus:

virtual ~Scanner() { ... }
virtual ~Scanner3D() { ... }
virtual ~Scanner3DLaserScanner { ... }

Maar als je die destructors niet virtual maakt, gaat het niet goed... Vroeg me eigenlijk af hoe dat werkt in C++.

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Vuistregel is dat zodra er een virtual functie in de classe is moet de destructor ook virtual zijn. De runtime weet namelijk niet welke destructor moet worden aangeroepen in het geval van een delete op een base class pointer, voorbeeld:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Base
{
public:
    virtual ~Base() {}
}

class Derived : public Base
{
public:
    virtual ~Derived() {}
}

int main()
{

    Base* derivedInstance = new Derived();
    delete derivedInstance;

    return 0;
}


Als de destructors in dit geval niet derived waren dan zo tijdens de delete enkel de Base destructor worden aangeroepen.
Trouwens zodra de base class een virtual destructor heeft hebben alle derived classes dat ook, dit is dezelfde regel die voor virtual op normale functies werkt.

[ Voor 26% gewijzigd door NC83 op 19-05-2010 22:23 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
Een destructor moet virtual zijn als de klasse als base-class dient (of kan gaan dienen). Als hij niet virtual is en een instantie van een subclass wordt verwijderd, dan wordt de destructor van de base niet aangeroepen en kan dit leiden tot een memory-leak.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Dat is iets te simpel. Policy classes zijn bijvoorbeeld een tegenvoorbeeld.

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


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
Mafkees schreef op woensdag 19 mei 2010 @ 12:03:
C++:
1
2
3
4
5
class Scanner
{
public:
    virtual bool Initialize() const = 0;
};
Het gebruik van Initialize methods is niet nodig in C++; daar bestaan echte constructors. Die zijn veel makkelijker. Zo roepen ze bijvoorbeeld standaard een base class constructor aan.

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

Pagina: 1