DLL a programowanie obiektowe

DLL a programowanie obiektowe
-CD-
  • Rejestracja:prawie 22 lata
  • Ostatnio:prawie 13 lat
  • Postów:157
0

Cześć,

Mój program ma podział na cześć "core" i "app". Chciałbym, żeby moduł core zawierał pewną strukturę klas. Podam tutaj prosty przykład z życia codziennego, żeby wiadomo było o co chodzi.

W module "core" ma znajdować się np. klasa "samochód", która wewnątrz ma klasy np "silnik". Coś w stylu:

Moduł "core":

Kopiuj
class Samochod {
private:
  Silnik* silnik;
public:
  Silnik* getSilnik() {
    return silnik;
  }  
  void setSilnik(Silnik* newSilnik) {
    silnik = newSilnik;
  }
}
 

Tak więc samochód ma możliwość podmiany silnika. I to znajduje się w module "core".

Teraz moduł "app" powinien korzystać z biblioteki "core" tak, by do stworzonego w "core" obiektu klasy samochód podać swój własny silnik np.

Moduł "app":

Kopiuj
 
Samochod* samochod = core.getSamochod();
Silnik* silnik = new SuperSilnik();
samochod->setSilnik(silnik);

Gdyby "core" było zwykłą bibliotekę *.lib nie byłoby problemu. Pytanie tylko, czy "core" może być biblioteką "dll"? Czy wówczas tego typu styl programowania byłby w miarę łatwy do osiągnięcia? Czy do dll też można w ten sposób przekazywać wskaźniki z aplikacji, która z niego korzysta i na ile jest to trudne do zrobienia? Pytam, bo nie mam w ogóle doświadczenia z dll.


Wszystko co robisz, rób najprościej jak to możliwe, ale nie prościej.
edytowany 4x, ostatnio: -CD-
OT
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad 11 lat
0

Gdyby "core" było zwykłą bibliotekę *.lib nie byłoby problemu. Pytanie tylko, czy "core" może być biblioteką "dll"?

To żadna różnica. Biblioteka dll może eksportować i klasy.

_13th_Dragon
  • Rejestracja:prawie 20 lat
  • Ostatnio:11 dni
0

tak nie da rady:

Kopiuj
Samochod* samochod = core.getSamochod();
Silnik* silnik = new SuperSilnik();
samochod->setSilnik(silnik);

tak spoko:

Kopiuj
Samochod* samochod = core.getSamochod();
Silnik* silnik = = core.getSuperSilnik();
samochod->setSilnik(silnik);

Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
Zobacz pozostałe 2 komentarze
Endrju
O czym Ty w sumie mówisz? Biblioteka + nagłówek i można tak robić.
Endrju
No tak właśnie robię. Mam klasy w dll/so, nagłówki i robię new. Wszystko działa, co ma nie działać? Dlaczego?
-CD-
czy robisz dokładnie w ten sposób? Tzn. przekazujesz wskaźnik do obiektu stworzonego z zewnątrz do dll'ki, która potem na tym obiekcie wykonuje operacje?
Endrju
Tak, to właśnie też teraz zrobiłem. (Tzn. to nie dll tylko so, chyba, że to tylko Windows jest w tej kwestii upośledzony?)
2

__declspec(dllexport/dllimport) przy deklaracji klasy i wszystko da radę.
Zaufaj mi, jestem inżynierem.

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:4 minuty
2

Da radę, jeśli biblioteka DLL i program będą kompilowane tym samym kompilatorem, najlepiej w tej samej wersji. Inaczej program nie będzie widział funkcji w DLL skompilowanych pod innym C++.

Azarien
co nie pod windows? w którym miejscu nie zgadza się to co napisałem?
_13th_Dragon
Może jakiś inny system to zadziała ale nie windows, jeżeli pamięć przydzielasz w programie to DLL tego w sposób łatwy nie odczyta.
-CD-
  • Rejestracja:prawie 22 lata
  • Ostatnio:prawie 13 lat
  • Postów:157
0

tak spoko:

Samochod* samochod = core.getSamochod();
Silnik* silnik = = core.getSuperSilnik();
samochod->setSilnik(silnik);

No i właśnie tak też gdzieś wyczytałem - że dll'ka nie może używać obiektów z zewnątrz. Sęk tylko w tym, że to przekreśla użycie dll'ki, bo z założenia jest to "core" a core nie ma posiadać wszystkich możliwych implementacji klasy Silnik. No chyba, żeby to zrobić tak, żeby użyć konstruktora kopiującego?

Kopiuj
 
Samochod* samochod = new Samochod(core.getSamochod());

Wówczas jak rozumiem mógłbym używać tego obiektu normalnie, bo tak naprawdę został stworzony lokalnie poprzez skopiowanie obiektu z core. Tylko ,ze to się robi już takie lekkie kombinowanie :/.

Widzę, ze jednak zdania są rozbieżne, więc poczekam jeszcze na inne opinie. Co do użycia tego samego kompilatora, to gwarancji nie mam, że będzie ten sam i w sumie nie powinienem tego zakładać. Trochę mi się jawi ta dll'ka jako źródło problemów :/, bo najgorsze, że (jak rozumiem) jeśli to się ma wysypać, to w trakcie działania, a tego bym baaardzo nie chciał.

Endrju - czy robisz dokładnie w ten sposób? Tzn. przekazujesz wskaźnik do obiektu stworzonego z zewnątrz do dll'ki, która potem na tym obiekcie wykonuje operacje?


Wszystko co robisz, rób najprościej jak to możliwe, ale nie prościej.
edytowany 2x, ostatnio: -CD-
OT
  • Rejestracja:ponad 20 lat
  • Ostatnio:ponad 11 lat
3

Da się, klasę całą można eksportować i normalnie używać dokładnie tak jak @Azarien napisał. Nie ma z tym żadnego problemu jeśli używasz tego samego kompilatora, którym kompilowałeś dll, ale inny kompilator C++ nie będzie mógł użyć tej dll-ki. Można to jednak obejść eksportując interfejs (na podobnej zasadzie działa np technologia COM) i używać dll-ki z każdym kompilatorem C++ ale wtedy nie jest eksportowana klasa bezpośrednio albo użyć smart pointerów.

Tutaj masz bardzo dobry artykuł z opisanymi możliwościami podejścia do tematu: http://www.codeproject.com/Articles/28969/HowTo-Export-C-classes-from-a-DLL

edytowany 4x, ostatnio: othello
_13th_Dragon
To może poczytaj uważnie ten link co podałeś, new ma być tylko w DLL, no chyba że DLL nigdy nie łazi po składowych obiektu.
Azarien
@_13th_Dragon: jeśli obie strony używają dynamicznie łączonej biblioteki CRT w tej samej wersji, to nie ma znaczenia gdzie jest new a gdzie delete.
_13th_Dragon
To może zrób prosty programik, DLL obliczającą odległość punktu od 0,0 gdzie obiekt struktury punkt przydzielony przez new w programie głównym.
adf88
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 12 lat
0
_13th_Dragon napisał(a)

Może jakiś inny system to zadziała ale nie windows, jeżeli pamięć przydzielasz w programie to DLL tego w sposób łatwy nie odczyta.

Nieprawda.

Załączam przykład. DLL tworzy obiekt na stercie. Aplikacja niszczy.

Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:4 minuty
1
_13th_Dragon napisał(a)

To może zrób prosty programik, DLL obliczającą odległość punktu od 0,0 gdzie obiekt struktury punkt przydzielony przez new w programie głównym.

delele.h

Kopiuj
#pragma once

#ifndef DELELEAPI
#define DELELEAPI
#endif

struct punkt
{
  double x, y;

  DELELEAPI punkt(double ax, double ay);
  DELELEAPI double odleglosc();
};

delele.cpp

Kopiuj
#define DELELEAPI __declspec(dllexport)

#include "delele.h"

#include <cmath>

DELELEAPI double punkt::odleglosc()
{
   return std::sqrt(x*x + y*y);
}

DELELEAPI punkt::punkt(double ax, double ay)
  : x(ax), y(ay)
{}

test.cpp

Kopiuj
#include "delele.h"

#include <iostream>
using namespace std;


int main()
{
   punkt *pkt = new punkt(3,4);
   cout << pkt->odleglosc() << endl;
   delete pkt;
}
Kopiuj
C:\PP\myprogs\odleg2>cl delele.cpp /LD
...
C:\PP\myprogs\odleg2>cl test.cpp delele.lib
...
C:\PP\myprogs\odleg2>test
5
edytowany 1x, ostatnio: Azarien
_13th_Dragon
  • Rejestracja:prawie 20 lat
  • Ostatnio:11 dni
1

Muszę przyznać że masz racje. Nawet rozszerzyłem to do:
delele.h:

Kopiuj
#pragma once
 
#ifndef DELELEAPI
#define DELELEAPI
#endif
 
struct punkt
{
  double x, y;
 
  DELELEAPI punkt(double ax, double ay);
  DELELEAPI double odleglosc();
};

DELELEAPI punkt *newpunkt(double ax, double ay);
DELELEAPI void deletepunkt(punkt *p);

delele.cpp:

Kopiuj
#define DELELEAPI __declspec(dllexport)
 
#include "delele.h"
 
#include <cmath>
 
DELELEAPI double punkt::odleglosc()
{
   return std::sqrt(x*x + y*y);
}
 
DELELEAPI punkt::punkt(double ax, double ay)
  : x(ax), y(ay)
{}

DELELEAPI punkt *newpunkt(double ax, double ay)
{
   return new punkt(ax,ay);
}

DELELEAPI void deletepunkt(punkt *p)
{
   delete p;
}

test.cpp:

Kopiuj
#include "delele.h" 
#include <iostream>
using namespace std;
 
 
int main()
{
   punkt *pkt=0;
   for(unsigned i=1;;++i)
     {
      cout<<'\r';

      pkt = new punkt(3,4);
      cout << pkt->x<<','<<pkt->y<<':'<< pkt->odleglosc() << " ; ";
      delete pkt;
   
      pkt = newpunkt(12,5);
      cout <<pkt->x<<','<<pkt->y<<':'<< pkt->odleglosc() << " ; ";
      deletepunkt(pkt);
   
      punkt *pkt = new punkt(8,6);
      cout << pkt->x<<','<<pkt->y<<':'<< pkt->odleglosc() << " ; ";
      deletepunkt(pkt);
   
      pkt = newpunkt(10,24);
      cout <<pkt->x<<','<<pkt->y<<':'<< pkt->odleglosc() << " ; ";
      delete pkt;

      cout<<i;
     }
   return 0;
}

I wszytko działa bez zarzutów.

Tylko teraz ja mam pytanie, czemu takie same coś nie działa w przypadku Delphi, może mam przestarzałe informacje z czasów Delphi5/WinXP.
Muszę to zbadać.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
Endrju
No widzisz! Przestraszyłeś mnie, że Windows jest upośledzony. :-P

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.