Dynamiczne łączenie klas z bibliotek DLL

dział ogólny

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez Cyfrowy Baron » wtorek, 16 lutego 2010, 13:12

Virtual destructor - plik pomocy Borland C++ Builder 2010:


Virtual DestructorsFrom RAD Studio
Go Up to Destructors Index


A destructor can be declared as virtual. This allows a pointer to a base class object to call the correct destructor in the event that the pointer actually refers to a derived class object. The destructor of a class derived from a class with a virtual destructor is itself virtual.

Kod: Zaznacz cały
/* How virtual affects the order of destructor calls.
   Without a virtual destructor in the base class, the derived
   class destructor won't be called. */
#include <iostream>
class color {
public:
   virtual ~color() {  // Virtual destructor
      std::cout << "color dtor\n";
      }
};
class red : public color {
public:
   ~red() {  // This destructor is also virtual
      std::cout << "red dtor\n";
      }
};
class brightred : public red {
public:
   ~brightred() {  // This destructor is also virtual
       std::cout << "brightred dtor\n";
       }
};
int main()
{
   color *palette[3];
   palette[0] = new red;
   palette[1] = new brightred;
   palette[2] = new color;
   // The destructors for red and color are called.
   delete palette[0];
   std::cout << std::endl;
   // The destructors for bright red, red, and color are called.
   delete palette[1];
   std::cout << std::endl;
   // The destructor for color is called.
   delete palette[2];
   return 0;
}

Program Output:

red dtor
color dtor
brightred dtor
red dtor
color dtor
color dtor


However, if no destructors are declared as virtual, delete palette[0], delete palette[1], and delete palette[2] would all call only the destructor for class color. This would incorrectly destruct the first two elements, which were actually of type red and brightred.

See Also
  • Class Initialization
  • Invoking Destructors
  • atexit, pragma exit, And Destructors
  • exit and Destructors
  • abort and Destructors

Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez polymorphism » wtorek, 16 lutego 2010, 13:25

Teraz wystarczy w pliku aplikacji w sekcji include włączyć plik #include suma.h. Nie będzie komunikatów błędu, tylko czy to nie jest to samo co z dołączeniem pliku suma.cpp?

Dokładnie to samo.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez Witold » wtorek, 16 lutego 2010, 13:26

polymorphism napisał(a):No właśnie nie, bo nie możesz podmienić klasie bazowej jej konstruktora/destruktora z poziomu klasy pochodnej - właśnie tu jest ta różnica między metodą a destruktorem. Dlatego, tak sądzę, pomimo tej umownej czystej wirtualności powinieneś zapewnić implementację takiemu destruktorowi (o ile chcesz tworzyć instancję tej klasy lub jej pochodnej).


Nie rozumiem, rozważamy klasę bazową abstrakcyjną (ma =0 przy metodzie/destruktorze), więc nie można stworzyć jej obiektu wiec jak jej mogę coś podmienić ?

Test z destruktorami:

Kod: Zaznacz cały
#include <iostream>
using namespace std;

class B
{
public:
    virtual ~B() = 0;
};

B::~B()
{
    cout << "~B\n";
}

class C : public B
{
public:
    ~C()
    {
        cout << "~C\n";
    }
};
int main()
{
  // C c;
    B * pb = new C;
    delete pb;
}

// wynik
// ~C
// ~B


Chyba zupełnie jak przy metodzie (+ destruktor klasy bazowej).
Ostatnio edytowano wtorek, 16 lutego 2010, 13:30 przez Witold, łącznie edytowano 1 raz
Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
Podziękował : 1
Otrzymał podziękowań: 14
Kompilator: bcb6, Turbo C++ Explorer
    AmigaAWeb

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez Cyfrowy Baron » wtorek, 16 lutego 2010, 13:30

A gdyby zamiast wywoływać destruktor z poziomu aplikacji stworzyć w klasie funkcje, która sama wywoływałaby destruktor:

suma.h
Kod: Zaznacz cały
class TSuma
{
       private:
          int a;
       public:
   TSuma();
        virtual ~TSuma(void);
   virtual dodawanie(int,int);
        virtual Free();

};


suma.cpp
Kod: Zaznacz cały
#include "suma.h"

TSuma::TSuma()
{

}
TSuma::~TSuma(void)
{

}
TSuma::Free()
{
   if(this) delete this;
}
double TSuma::dodawanie(int a, int b)
{
        return (a+b);
}


w pliku aplikacji zamiast delete suma, suma->Free();
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez polymorphism » wtorek, 16 lutego 2010, 14:05

Nie rozumiem, rozważamy klasę bazową abstrakcyjną (ma =0 przy metodzie/destruktorze), więc nie można stworzyć jej obiektu wiec jak jej mogę coś podmienić ?

Heh, chyba się nie zrozumieliśmy ;) Chodziło mi o taką klasę:
Kod: Zaznacz cały
class B
{
public:
    virtual ~B() = 0; //<-- taki typowy 'pure virtual'
};

Na bazie takiej klasy nic nie stworzysz (w sensie instancji), zapewnienie dtor'a w klasie pochodnej nic nie da, w przeciwieństwie do metod, więc taka konstrukcja jest mało praktyczna. I dlatego pisałem o umownej, czystej wirtualności destruktora.

Z kolei we wcześniejszym poście napisałeś:
Wydaje mi się że metoda/destruktor jest pure virtual gdy jest oznaczona/y =0, bez znaczenia czy ma ciało czy nie.

Chodziło mi głownie o to "ciało". W przypadku destruktora - zgoda, w przypadku metod - nie. Nie da się zdefiniować metod czysto wirtualnych z ciałem (w każdym razie ja nic o tym nie wiem). Tylko o to mi chodziło.

___
p.s. znowu wątek zszedł na boczne tory :mrgreen:
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez polymorphism » wtorek, 16 lutego 2010, 14:09

A gdyby zamiast wywoływać destruktor z poziomu aplikacji stworzyć w klasie funkcje, która sama wywoływałaby destruktor (...)

Nie no, taką sugestię rafalskraba dostał TU i TU. Zresztą cały temat o pisaniu wtyczek rozwiązuje problem.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez Cyfrowy Baron » wtorek, 16 lutego 2010, 14:11

Więc nie rozumiem w czym tkwi problem, skoro wywołanie destruktora z poziomu funkcji rozwiązuje ten problem.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez polymorphism » wtorek, 16 lutego 2010, 14:23

W sumie w niczym 8-) Tak sobie luźno dywagujemy z Witoldem o destruktorach czysto wirtualnych.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez Witold » wtorek, 16 lutego 2010, 15:55

polymorphism napisał(a):Heh, chyba się nie zrozumieliśmy ;) Chodziło mi o taką klasę:
Kod: Zaznacz cały
class B
{
public:
    virtual ~B() = 0; //<-- taki typowy 'pure virtual'
};

Na bazie takiej klasy nic nie stworzysz (w sensie instancji), zapewnienie dtor'a w klasie pochodnej nic nie da, w przeciwieństwie do metod, więc taka konstrukcja jest mało praktyczna.


Nie da, bo będzie potrzebny destruktora tej klasy (bazowej), a on w tym wypadku niema ciała. Ja rozumiem to tak gdy dodam:

Kod: Zaznacz cały
class C : public B
{
public: 
};

dostanę gratis destruktor:

Kod: Zaznacz cały
C::~C()
{
   // na końcu
     B::~B(); //<- tu jest problem, ~B() nie ma definicji
}


polymorphism napisał(a):I dlatego pisałem o umownej, czystej wirtualności destruktora.


Rozumiem (chyba) o co Ci chodzi ale nie pasuje mi ta "umownej", destruktor=0 wykazuje te same cechy jak metoda=0.

1) ma =0 (jest pure virtual)
2) czyni klasę abstrakcyjną
3) musi być dostarczona jego implementacja w pochodnych klasach

polymorphism napisał(a):Nie da się zdefiniować metod czysto wirtualnych z ciałem (w każdym razie ja nic o tym nie wiem). Tylko o to mi chodziło.


Kod: Zaznacz cały
class B
{
public:
    virtual void f()=0;
};

void B::f()
{
    cout << "void B::f() =0;\n";
}

class C : public B
{
public:
    void f()   {   B::f();  }
};

int main()
{
    B * pb = new C;
    pb->f();
    delete pb;
}


wynik:
void B::f() =0;


Edit: zagalopowałem się z tym dodawaniem destruktora ~C(), hmm może jednak nie
Ostatnio edytowano wtorek, 16 lutego 2010, 18:55 przez Witold, łącznie edytowano 1 raz
Avatar użytkownika
Witold
Konstrukcjonista
Konstrukcjonista
 
Posty: 223
Dołączył(a): piątek, 29 sierpnia 2008, 10:53
Podziękował : 1
Otrzymał podziękowań: 14
Kompilator: bcb6, Turbo C++ Explorer
    AmigaAWeb

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez polymorphism » wtorek, 16 lutego 2010, 16:28

3) musi być dostarczona jego implementacja w pochodnych klasach

No a jak dostarczysz? Każda klasa ma/powinna mieć swój własny destruktor. Jak dla mnie punkt 2 ma jedynie praktyczne uzasadnienie stosowania takich destruktorów.

wynik:
void B::f() =0;

No faktycznie można, nie wiedziałem. Sprawa wygląda podobnie jak z destruktorem czysto wirtualnym, tego typu metody nigdy do niczego nie były mi potrzebne, w źródłach innych projektów także nie spotkałem się z czymś takim (a wiele widziałem), więc i moja wiedza w tym temacie jest niekompletna :roll:

--- edit ---
Edit: zagalopowałem się z tym dodawaniem destruktora ~C().

Dlaczego? Można śmiało założyć, ze domyślny dtor/ctor zawsze istnieje, bo to, czy jest on w rzeczywistości wygenerowany przez kompilator, czy też nie, nie ma aż takiego znaczenia - sposób zachowania klasy jest taki sam.
Ostatnio edytowano wtorek, 16 lutego 2010, 16:42 przez polymorphism, łącznie edytowano 1 raz
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez rafalskraba » wtorek, 16 lutego 2010, 17:26

Spróbuję stworzyć klasę pośredniczącą pomiędzy klasą TSuma a aplikacją. Klasę tą umieszczę w bibliotece dll i jej metody będę expotrował z biblioteki.
Nie wiem czy ten tok rozumowanie jest prawidłowy proszę o opinie.
"Jednym z rodzajów szczęśliwości jest zdolność podejmowania dobrych decyzji."

- Platon-
Avatar użytkownika
rafalskraba
Intelektryk
Intelektryk
 
Posty: 122
Dołączył(a): czwartek, 5 marca 2009, 10:20
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: Windows 7 x64
Kompilator: RAD Studio XE2 Update 4 HotFix 1
SKYPE: rafal.skraba
Gadu Gadu: 0
    Windows 7Firefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez polymorphism » wtorek, 16 lutego 2010, 18:38

No nie jest. Czy w wątku, który Ci poleciłem na początku tego tematu, klasa IPlugin cokolwiek eksportuje/importuje?
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez rafalskraba » wtorek, 16 lutego 2010, 23:50

Program zmodyfikowałem następująco i kompilacja przebiegła bezproblemowo.

1. plik *.h biblioteki dll
Kod: Zaznacz cały
class TSuma
{
   private:
      int n;
   public:
      TSuma();
      //virtual ~TSuma();
      double virtual suma(int,int);
};

2. plik *.cpp biblioteki dll
Kod: Zaznacz cały
TSuma::TSuma()
{
   
}
double TSuma::suma(int a, int b)
{
    return (a+b);
}


2. export funkcji z dll
Kod: Zaznacz cały
extern "C" __declspec(dllexport) TSuma* Test()
{
   TSuma* aa = new TSuma;
   return aa;
}


2. plik *.cpp aplikacji
Kod: Zaznacz cały
         typedef TSuma* (*Test4)();


   HINSTANCE sciezka;
   sciezka = LoadLibrary("suma.dll");
   if(sciezka == NULL)
   {
      ShowMessage("Brak biblioteki DLL");
      return;
   }
   Test4 przyklad=(Test4)GetProcAddress(sciezka,"_Test");
   if(!przyklad)
   {
   ShowMessage("Nie znaleziono funkcji");
   return;

   }

      TSuma* aa=(przyklad)();
      Label1->Caption=aa->suma(A,B);
          delete aa;
          aa = NULL;
          FreeLibrary(sciezka);


Generalnie z kodu źródłowego klasy TSuma zawartego w bibliotece dll pominąłem destruktor klasy. Obiekt 'aa' jak również klasa TSuma są usuwane z pamięci
poprzez delete aa; oraz FreeLibrary.

Nie jestem pewien czy takie rozwiązanie jest poprawne proszę o opinie.
"Jednym z rodzajów szczęśliwości jest zdolność podejmowania dobrych decyzji."

- Platon-
Avatar użytkownika
rafalskraba
Intelektryk
Intelektryk
 
Posty: 122
Dołączył(a): czwartek, 5 marca 2009, 10:20
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: Windows 7 x64
Kompilator: RAD Studio XE2 Update 4 HotFix 1
SKYPE: rafal.skraba
Gadu Gadu: 0
    Windows 7Firefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez polymorphism » środa, 17 lutego 2010, 10:54

A co jest po stronie aplikacji? Chodzi mi o definicję klasy TSuma.

Pisałem też o zarządzaniu pamięcią tych obiektów...

___
p.s. przejrzałeś wątek, który Ci poleciłem? Pytam, bo odnoszę jakieś dziwne wrażenie, że nie.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    Windows XPFirefox

Re: Dynamiczne łączenie klas z bibliotek DLL

Nowy postprzez rafalskraba » środa, 17 lutego 2010, 23:26

Oczywiście przejrzałem ten post ktory mi podaleś, jednakże ja mam prostą klasę narazie nie będę w niej korzystał z dziedziczenia wyeksportowalem dodatkowo funkcje która usuwa obiekt TSuma. Teraz myślę ze jest wszystko wporządku.
Plik *.h biblioteki dll

Kod: Zaznacz cały
# define DLLIMPORT __declspec (dllexport)
#else
# define DLLIMPORT __declspec (dllimport)
#endif

class DLLIMPORT TSuma
{
   public:
      TSuma();
      virtual ~TSuma();
      virtual double suma(int,int);
};


Plik *.cpp biblioteki

Kod: Zaznacz cały
TSuma::TSuma()
{

}
TSuma::~TSuma()
{

}
double TSuma::suma(int a, int b)
{
    return (a+b);
}


Funkcje wyeksportowane z biblioteki dll

Kod: Zaznacz cały
extern "C" __declspec(dllexport) TSuma* Test()
{
   return new TSuma;
}
extern "C" __declspec(dllexport) void Delete(TSuma* del)
{
   delete del;
}


Kod źródłowy aplikacji

Kod: Zaznacz cały
        typedef TSuma* (*Test)();
   typedef void (*Delete)(TSuma* aa);
   HINSTANCE sciezka;
   sciezka = LoadLibrary("suma.dll");
   if(sciezka == NULL)
   {
      ShowMessage("Brak biblioteki DLL");
      return;
   }
      Test _Test =(Test)GetProcAddress(sciezka,"_Test");
      Delete _Delete = (Delete)GetProcAddress(sciezka,"_Delete");
      if(!_Delete)
   {
      ShowMessage("Nie znaleziono funkcji");
      return;

   }
      Form1->StatusBar1->Panels->Items[0]->Text="Znaleziono funkcję";
      TSuma* aa = (_Test)();
                aa->suma(5,6);
      _Delete(aa);

         FreeLibrary(sciezka);
"Jednym z rodzajów szczęśliwości jest zdolność podejmowania dobrych decyzji."

- Platon-
Avatar użytkownika
rafalskraba
Intelektryk
Intelektryk
 
Posty: 122
Dołączył(a): czwartek, 5 marca 2009, 10:20
Podziękował : 2
Otrzymał podziękowań: 0
System operacyjny: Windows 7 x64
Kompilator: RAD Studio XE2 Update 4 HotFix 1
SKYPE: rafal.skraba
Gadu Gadu: 0
    Windows 7Firefox

Poprzednia stronaNastępna strona

  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 12 gości

cron