DLL a programowanie obiektowe

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":

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":

 
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.

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.

0

tak nie da rady:

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

tak spoko:

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

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

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++.

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?

 
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?

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

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.

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

#pragma once

#ifndef DELELEAPI
#define DELELEAPI
#endif

struct punkt
{
  double x, y;

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

delele.cpp

#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

#include "delele.h"

#include <iostream>
using namespace std;


int main()
{
   punkt *pkt = new punkt(3,4);
   cout << pkt->odleglosc() << endl;
   delete pkt;
}
C:\PP\myprogs\odleg2>cl delele.cpp /LD
...
C:\PP\myprogs\odleg2>cl test.cpp delele.lib
...
C:\PP\myprogs\odleg2>test
5
1

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

#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:

#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:

#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ć.

1 użytkowników online, w tym zalogowanych: 0, gości: 1