C++ Pointer auf abstrakte Klasse

Freezedevil

Lieutenant
Registriert
Mai 2011
Beiträge
640
Hi,
ich bin grade dabei auszuprobieren wie man eine Art Pluginmechanismus bewerkstelligen kann. Dazu habe ich eine abstrakte Klasse Scheduler erstellt von der dann die einzelnen "Plugins" erben und konkrete Strategien implementieren können. Damit später ohne Änderungen am Code zusätzliche Plugin benutzt werden können, sollen diese als Shared Object zur Laufzeit geladen werden. Meine Idee war also im Hauptprogramm einen Pointer vom Typ Scheduler auf die konkrete aktuell geladene Klasse zu haben. Allerdings sagt mir der Compiler, dass ich kein Objekt einer abstrakten Klasse anlegen kann, aber das versuche ich nach meinem Verständnis ja auch gar nicht. Eventuell sieht jemand von euch den Fehler und kann Licht in mein Dunkel bringen, denn mit einem Minimalbeispiel (folgt am Ende) funktioniert die Sache wie ich es mir vorstelle. Lange Rede kurzer Sinn.

Edit: OS ist Ubuntu 12.10

Fehler beim Compilieren:
Code:
main.cpp: In Funktion »int main(int, char**)«:
main.cpp:32:37: Fehler: es kann kein Objekt des abstrakten Typs »Scheduler« belegt werden
In file included from main.cpp:4:0:
Scheduler.h:6:7: Anmerkung:   denn die folgenden virtuellen Funktionen sind rein innerhalb »Scheduler«:
Scheduler.h:11:22: Anmerkung: 	virtual std::string Scheduler::say()
make: *** [all] Fehler 1

Entsprechender Programmcode:
main.cpp
Code:
#include <iostream>
#include <dlfcn.h>

#include "Scheduler.h"

using namespace std;

int main (int argc, char* argv[]) {
    void* lib = dlopen("schedFill.so", RTLD_LAZY);

    if (!lib) {
        cerr << "Cannot load library: " << dlerror() << '\n';
        return 1;
    }
    // reset errors
    dlerror();

    create_fp* create_sched = (create_fp*) dlsym(lib, "create");
    const char* dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol create: " << dlsym_error << endl;
        return 1;
    }

    destroy_fp* destroy_sched = (destroy_fp*) dlsym(lib, "destroy");
    dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol destroy: " << dlsym_error << endl;
        return 1;
    }

    Scheduler* sched = create_sched();
    sched->say();
    destroy_sched(sched);

    dlclose(lib);

	return 0;
}

Scheduler.h
Code:
#ifndef SCHEDULER_H
#define SCHEDULER_H

#include <iostream>

class Scheduler {
public:
	Scheduler() {};
	virtual ~Scheduler() {}

	virtual std::string say() = 0;
};

typedef Scheduler create_fp();
typedef void destroy_fp(Scheduler*);

#endif

SchedulerFill.h
Code:
#ifndef SCHEDULERFILL_H
#define SCHEDULERFILL_H

#include "Scheduler.h"

class SchedulerFill : public Scheduler {
public:
	SchedulerFill();
	~SchedulerFill();
	std::string say();
};

#endif

Schedulerfill.cpp
Code:
#include "SchedulerFill.h"

SchedulerFill::SchedulerFill() {}

SchedulerFill::~SchedulerFill() {}

std::string SchedulerFill::say() {
	std::string test = "fill";
	return test;
}

extern "C" SchedulerFill* create() {
	SchedulerFill* sched = new SchedulerFill();
	return sched;
}

extern "C" void destroy(Scheduler* sched) {
	delete sched;
}


Funktionierendes Minimalbeispiel:
Code:
#include <iostream>
using namespace std;

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

class B : public A {
public:
	B() {}
	~B() {}
	void f() {
		cout << "test" << endl;
	}
};

int main(int argc, char** argv) {
	A* test = new B();
	test->f();
	return 0;
}
 
Zuletzt bearbeitet:
naja deine function say() ist virtuell, dann muss deine abgeleite Klasse auch das Wort virtual vor say() haben, so wie es jetzt ist findet der Compiler keine Implementation zur rein virtuellen say() function und ist daher weiterhin abstract.

ByTheWay

verstehe auch nicht was das soll

typedef Scheduler create_fp(); ( du hast den Stern nach Scheduler vergessen, somit versucht diese eine Instanz und keinen Pointer zurückzugeben )
typedef void destroy_fp(Scheduler*);

Du definierst 1. eine Funktion auf eine Klasse ???
Du definierst 2. einen Funktionsprototyp auf void (nix), wie macht das Sinn, sry wenn ich hier der Dumme bin, man lernt ja nie aus xD

EDIT: Ok das sind Funktionspointer, wenn das funktioniert ok,
ich hätte das aber so aussehen lassen:

typedef Scheduler (*create_fp)(void);
typedef void (*destroy_fp)(Scheduler*);

EDIT: Ok im Minimalbeispiel ist natürlich kein virtual erforderlich um zu funzen

Ich hab das Projekt mal bei mir aufgesetzt:

LÖSUNG
statt typedef Scheduler (*create_fp)(void);
einfach typedef Scheduler* (*create_fp)(void); benutzen, lol diese tricky Syntax immer

BEMERKUNG:

Wenn du diese Syntax verwendest:

typedef Scheduler* (*create_fp)(void);

kannst du einfach eine Variable des Typs Funktionspointer deklarien und casten

create_fp create_sched = (create_fp) dlsym(lib, "create"); (--> also ohne den Stern)
 
Zuletzt bearbeitet:
@Simpson: Vielen Dank, ymmd. Das hätte ich wahrscheinlich in Tagen nicht gefunden.

@gerdb: Wenn ich nur den "Tip" von Simpson umsetze geht es, aber ich glaube du hast prinzipiell trotzdem Recht. Habs geändert.

Richtig muss es also wie folgt lauten;
Code:
typedef Scheduler* create_fp();

Nochmal riesen Dank an euch beide, vor allem an Simpson (ich freu mich grad total^^).
Ergänzung ()

gerdb schrieb:
ByTheWay

verstehe auch nicht was das soll

typedef Scheduler create_fp();
typedef void destroy_fp(Scheduler*);

Du definierst 1. eine Funktion auf eine Klasse ???
Du definierst 2. einen Funktionsprototyp auf void (nix), wie macht das Sinn, sry wenn ich hier der Dumme bin, man lernt ja nie aus xD

EDIT: Ok das sind Funktionspointer, wenn das funktioniert ok,
ich hätte das aber so aussehen lassen:

typedef Scheduler (*create_fp)(void);
typedef void (*destroy_fp)(Scheduler*);

Ja ich hab auch vor das in dieser Syntax zu machen, da mir die Sache so wie es oben ist irgendwie auch nicht geheuer ist. Ich hab die Syntax aber erstmal so aus einem Tutorial übernommen gehabt um Fehler an dieser Stelle auszuschließen.
Kann jemand mal die Unterschiede zwischen
Code:
typedef Scheduler create_fp();
typedef void destroy_fp(Scheduler*);
und
Code:
typedef Scheduler (*create_fp)(void);
typedef void (*destroy_fp)(Scheduler*);
erklären. Meinem Verständnis nach sollten sie eigentlich äquivalent sein, jedoch bekommen ich im zweiten Fall folgenden Fehler:
Code:
main.cpp: In Funktion »int main(int, char**)«:
main.cpp:32:37: Fehler: »create_sched« kann nicht als Funktion verwendet werden
main.cpp:34:24: Fehler: »destroy_sched« kann nicht als Funktion verwendet werden
make: *** [all] Fehler 1
 
Um ehrlich zu sein, deinen Syntax habe ich bisher auch noch nicht verwendet.
Code:
typedef Scheduler create_fp();
typedef void destroy_fp(Scheduler*);
create_fp* create_sched = (create_fp*) dlsym(lib, "create");
destroy_fp* destroy_sched = (destroy_fp*) dlsym(lib, "destroy");

Der Pointer ist in diesem Fall ja bereits im Typ enthalten:
Code:
typedef Scheduler (*create_fp)(void);
typedef void (*destroy_fp)(Scheduler*);
create_fp create_sched = (create_fp) dlsym(lib, "create");
destroy_fp destroy_sched = (destroy_fp) dlsym(lib, "destroy");
 
Ja das ist logisch. Ich sollte langsam Schluss für heute machen.

So es läuft jetzt und benutzt die von euch, mir und 99,99% des Internets präferierten Syntax, weshalb ich erstmal wunschlos glücklich bin.
Vielen Dank für die erneute Erklärung.
 
gerdb schrieb:
naja deine function say() ist virtuell, dann muss deine abgeleite Klasse auch das Wort virtual vor say() haben, so wie es jetzt ist findet der Compiler keine Implementation zur rein virtuellen say() function und ist daher weiterhin abstract.

Ne nee, in C++ gilt "ein mal virtual, immer virtual". ;)
 

Ähnliche Themen

Zurück
Oben