Forum: PC-Programmierung C++ Klassen für DLL exportieren und von dieser erben


von Patrick B. (p51d)


Lesenswert?

Hallo zusammen

Ich stosse bis jetzt immer wieder an die gleichen Probleme und möchte 
etwas effizienter werden.
Die Basis meiner Devices ist immer die selbe. Nur die Funktion variiert. 
Damit die Basis und die Hardware Abstraktion nicht jedes mal neu codiert 
werden muss, würde ich das ganze gerne mit DLLs umgehen.

Die Basis Hardware Abstraktion sieht in etwa so aus.
1
///////////////////////////////////////////////////////////////
2
/// This class contains all informations about the ident
3
/// structure (Unit version, interface version, article number...)
4
///////////////////////////////////////////////////////////////
5
class CIdent
6
{
7
private:
8
    CModbusMaster& m_roModbusMaster;
9
 
10
public:
11
    static const uint8_t c__u8ArticleNumberLength = 20;
12
   
13
    CIdent(CModbusMaster& p_roModbusMaster);
14
    ~CIdent();
15
   
16
    bool bGetArticleNumber(char* p_pcarticleNumber, const uint8_t p__u8BufferSize);
17
};
18
 
19
///////////////////////////////////////////////////////////////
20
/// This class contains all informations about the standard
21
/// components on the device.
22
///////////////////////////////////////////////////////////////
23
class CNumberOfComponents
24
{
25
private:
26
    CModbusMaster& m_roModbusMaster;
27
 
28
public:
29
    CNumberOfComponents(CModbusMaster& p_roModbusMaster);
30
    ~CNumberOfComponents();
31
   
32
    bool bGetNumberOfInputs(uint8& p_ru8NumberOfInputs);
33
};
34
 
35
 
36
///////////////////////////////////////////////////////////////
37
/// Base Class for any devcies
38
///////////////////////////////////////////////////////////////
39
class CDevice
40
{
41
private:
42
    CModbusMaster& m_roModbusMaster;
43
 
44
public:
45
    CDevice(CModbusMaster& p_roModbusMaster);
46
    ~CDevice();
47
   
48
    CIdent m__oBootloader;
49
    CIdent m__oMainApplication;
50
   
51
    CNumberOfComponents m__oNumberOfComponents;
52
};

Die "richtigen" Devices würden dann von dieser Basis aus spezialisiert 
werden. Das könnte in etwa so aussehen:
1
///////////////////////////////////////////////////////////////
2
/// Device 1
3
///////////////////////////////////////////////////////////////
4
class CDevice1 : public CDevice
5
{
6
private:
7
    CModbusMaster& m_roModbusMaster;
8
 
9
public:
10
    CDevice1(CModbusMaster& p_roModbusMaster);
11
    ~CDevice1();
12
   
13
    void vFunction1();
14
    void vFunction2();
15
};
16
 
17
///////////////////////////////////////////////////////////////
18
/// Device 2
19
///////////////////////////////////////////////////////////////
20
class CDevice2 : public CDevice
21
{
22
private:
23
    CModbusMaster& m_roModbusMaster;
24
 
25
public:
26
    CDevice2(CModbusMaster& p_roModbusMaster);
27
    ~CDevice2();
28
   
29
    void vFunction1();
30
    void vFunction2();
31
};

Da ich bis jetzt nur DLLs benutzt, diese aber nie selber erstellt habe 
bin ich etwas ratlos.
Wie kann/muss ich das nun lösen?
- Eine DLL für die Basis und für jedes Device eine, die von der Basis 
"erbt" (geht das überhaupt?)
- Eine einzelne DLL für die Kombination Basis+Device

Gruss
P51D

von Dr. Sommer (Gast)


Lesenswert?

Patrick B. schrieb:
> Wie kann/muss ich das nun lösen?
> - Eine DLL für die Basis und für jedes Device eine, die von der Basis
> "erbt" (geht das überhaupt?)
> - Eine einzelne DLL für die Kombination Basis+Device
Beides geht, du musst du selber entscheiden, was sinnvoller ist... Will 
man jedes Device einzeln austauschen können, oder nutzt man immer eine 
Sammlung an Devices auf einmal, die man so ein eine DLL zusammen packen 
könnte? Prinzipiell kannst du deine Klassen beliebig auf DLL's 
aufteilen, solange keine Klasse doppelt vorkommt.

Du solltest deine Destruktoren in der Basisklasse übrigens besser auf 
"virtual" setzen, denn sonst wird der Destruktor der abgeleiteten Klasse 
ggf. nicht aufgerufen.

von Patrick B. (p51d)


Lesenswert?

Mhm, ich habe mir mal ein kleines Projekt aufgesetzt... und schon mit 
Problemen:
1
class Base
2
{
3
    ...
4
};
5
6
class Data
7
{
8
    ...
9
};
10
11
// MS Visual C++ compiler emits C4275 warning about not exported base class.
12
class __declspec(dllexport) Derived :
13
    public Base
14
{
15
    ...
16
17
public:
18
    Data m_data;    // C4251 warning about not exported data member.
19
};

Muss ich hier jetzt eine C-Wrapper Schnittstelle machen? Weil eine 
abstrake Interface-Klasse geht ja nicht, da die Member sonst nicht 
vefügbar sind.

Gruss

von Dr. Sommer (Gast)


Lesenswert?

Ich kenn mich mit der Windows-DLL-Angelegenheit jetzt nicht so aus, hab 
das ewig nicht mehr gemacht...

Patrick B. schrieb:
> Muss ich hier jetzt eine C-Wrapper Schnittstelle machen?
Eigentlich nicht.

Patrick B. schrieb:
> Weil eine
> abstrake Interface-Klasse geht ja nicht, da die Member sonst nicht
> vefügbar sind.
Hä? Geht genauso wie ohne DLL

Patrick B. schrieb:
> // MS Visual C++ compiler emits C4275 warning about not exported base
> class.
Dann exportier die Basis Klasse halt?

von lalala (Gast)


Lesenswert?

Warum eine DLL, und nicht einfach nur andere Compilationseinheiten und 
mit dem Linker zusammenlinken?

DLL mit C++ hat den Nachteil, dass das 'name mangling' 
Compiler-versionsspecifisch ist. D.h. keine Vorteil zu dem von mir oben 
geschriebenen Ansatz (eher sogar Nachteile).

Natürlich könnte man es auch so machen:
https://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL
(den mature approach)

Wenn Du das Ding nicht herausgeben willst / mit nicht C++ verwenden 
willst, lass die DLL.

von Meinungsmache (Gast)


Lesenswert?

In Zeiten des unendlichen Speicher haben DLLs für Endanwendungen ihre 
Berechtigung verloren. Sie machen nur Probleme durch falsche Version 
oder glänzen durch Abwesenheit. LIBs sind eine adäquate Möglichkeit für 
Vorfertigung von Modulen. Am Ende alles zu einer EXE verlinkt und man 
ist sich sicher alles komplett zu haben.

von Dr. Sommer (Gast)


Lesenswert?

Der Vorteil an DLL's ist, dass man sie austauschen kann, ohne die sie 
verwendenden Programm ändern zu müssen (wenn man es richtig gemacht 
hat). So kann man Fehlerbehebungen und Sicherheitsprobleme automatisch 
für alle Anwendungen übernehmen (auch wenn man deren Quellcode nicht 
hat). Ansonsten haben sie aber eine Menge Nachteile. Das funktioniert 
z.B. bei Java alles besser...

von Noch einer (Gast)


Lesenswert?

> abstrake Interface-Klasse

Die Qt hat da einen Trick. Die benutzen Klassen, die nur Funktionen 
enthalten und deren H-Dateien niemals verändert wird. Jede Klasse hat 
dann einen privaten Zeiger auf eine zusätzliche Klasse, die nicht 
exportiert wird.

von Noch einer (Gast)


Lesenswert?

>In Zeiten des unendlichen Speicher haben DLLs für Endanwendungen ihre
>Berechtigung verloren.

Eigentlich absurd. Erst machen wir so einen Aufwand mit den DLLs, dann 
verpacken wir die Programme mitsamt eigenen DLLs in Docker oder Snappy.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.