Problem beim Export bzw. Import von Templates bei dll



  • Also ich hab ein seltsames Problem. In einem Projekt das ich von VS 6 auf VS2005 übernommen hab verwende ich viele Templates.
    Ich exportiere diese Templateklassen in der DLL und importiere sie später in meinem testprogramm ... naja soweit so gut. Unter VS 6 hat es ja einwandfrei funktioniert ... nur unter 2005 bekomm ich lästige linkerfehler.

    wegbekommen tu ich das ganze nur wenn ich die export bzw. importroutinen (sind jeweils die gleichen dateien werden aber ggf. durch präprozessoranweisung auf import oder export gepolt) weglasse (Was ja auch logisch ist wenn es nicht mehr exportiert wird und logischer weise nicht mehr importiert)

    ich kann meine projekte auch wahlweise auf statisches linken umstellen ... dort logischerweise auch kein fehler.

    Nur warum geht es in dem einen und im anderen nicht und wo ist der sinn bzw. unsinn in diesem verhalten.

    ich hab mal den code so weit vereinfacht dass ihn - so hoffe ich - auch andere leute verstehen können. die sourcecode doku ist zum teil noch drin sollte auch zur verständlichkeit beitragen.

    also an namespaces wie mlib oder so liegt es nicht ... wie gesagt und vs6 läuft der spass ja ...

    das steht in der dll

    class __declspec(dllexport) MFunctor
    {
      public:
        /** @brief Default Constructor.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor( void )
        {
        } 
    
        /** @brief Copy Constructor.
          *
          * @param func zu kopierendes Functor-Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor(
          const MFunctor& func
        )
        {     
        }
    
        /** @brief Destructor.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual ~MFunctor( void ) throw()
        {
        }
    
        /** @brief Klonen des Functor-Objekts
          *
          * @return Zeiger auf das neu erzeugte, geklonte Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual MFunctor* Clone( void ) = 0 ;
    
        /** @brief Ausfuehren der Methode des Klassenobjekts.
          *
          * @param arg Methodenargument
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual void Execute(
          const MFunctorArg& arg
        ) = 0 ;
    };
    
    template < class TObject >
    class __declspec(dllexport) MFunctor0Tmpl : public MFunctor
    {
      public:
        /** Typedef fuer den Funktionstyp */
        typedef void (TObject::*PClassCB)( void ) ;
    
        /** @brief Default Constructor.
          *
          * Der Konstruktor initialisiert das Functor-Objekt, in dem er sich die Objektadresse
          * sowie die Methodenadresse der Objektinstanz merkt.
          *
          * @param object Zeiger auf das Objekt das die Methode enthaehlt 
          * @param method Zeiger auf die Methode
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor0Tmpl(
          TObject& object,
          PClassCB method
        ) : mObject( &object ), mMethod( method )
        {
        }
    
        /** @brief Copy Constructor.
          *
          * @param functor zu kopierendes Functor-Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor0Tmpl(
          const MFunctor0Tmpl< TObject >& functor
        ) : mObject( functor.mObject ), mMethod( functor.mMethod )
        {
        }
    
        /** @brief Destructor.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual ~MFunctor0Tmpl( void ) throw()
        {
        }
    
        /** @brief Klonen des Functor-Objekts
          *
          * @return Zeiger auf das neu erzeugte, geklonte Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual MFunctor* Clone( void )
        {
          return new MFunctor0Tmpl< TObject >( *this ) ;
        }
    
        /** @brief Ausfuehren der Methode des Klassenobjekts.
          *
          * @param arg Methodenargument
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual void Execute( const MFunctorArg& arg = MFunctorArg() )
        {
          (mObject->*mMethod)() ;
        }
    
      private:
        /** Zeiger auf das Objekt, dessen Methode ausgefuehrt werden soll. */
        TObject* mObject;                 
    
        /** Funktionszeiger auf die Objektmethode */
        PClassCB mMethod ;
    } ;
    

    das in meinem testprogramm

    class __declspec(dllimport) MFunctor
    {
      public:
        /** @brief Default Constructor.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor( void )
        {
        } 
    
        /** @brief Copy Constructor.
          *
          * @param func zu kopierendes Functor-Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor(
          const MFunctor& func
        )
        {     
        }
    
        /** @brief Destructor.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual ~MFunctor( void ) throw()
        {
        }
    
        /** @brief Klonen des Functor-Objekts
          *
          * @return Zeiger auf das neu erzeugte, geklonte Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual MFunctor* Clone( void ) = 0 ;
    
        /** @brief Ausfuehren der Methode des Klassenobjekts.
          *
          * @param arg Methodenargument
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual void Execute(
          const MFunctorArg& arg
        ) = 0 ;
    };
    
    template < class TObject >
    class __declspec(dllimport) MFunctor0Tmpl : public MFunctor
    {
      public:
        /** Typedef fuer den Funktionstyp */
        typedef void (TObject::*PClassCB)( void ) ;
    
        /** @brief Default Constructor.
          *
          * Der Konstruktor initialisiert das Functor-Objekt, in dem er sich die Objektadresse
          * sowie die Methodenadresse der Objektinstanz merkt.
          *
          * @param object Zeiger auf das Objekt das die Methode enthaehlt 
          * @param method Zeiger auf die Methode
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor0Tmpl(
          TObject& object,
          PClassCB method
        ) : mObject( &object ), mMethod( method )
        {
        }
    
        /** @brief Copy Constructor.
          *
          * @param functor zu kopierendes Functor-Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        MFunctor0Tmpl(
          const MFunctor0Tmpl< TObject >& functor
        ) : mObject( functor.mObject ), mMethod( functor.mMethod )
        {
        }
    
        /** @brief Destructor.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual ~MFunctor0Tmpl( void ) throw()
        {
        }
    
        /** @brief Klonen des Functor-Objekts
          *
          * @return Zeiger auf das neu erzeugte, geklonte Objekt.
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual MFunctor* Clone( void )
        {
          return new MFunctor0Tmpl< TObject >( *this ) ;
        }
    
        /** @brief Ausfuehren der Methode des Klassenobjekts.
          *
          * @param arg Methodenargument
          *
          * @throws Diese Methode generiert keine Exception.
        */
        virtual void Execute( const MFunctorArg& arg = MFunctorArg() )
        {
          (mObject->*mMethod)() ;
        }
    
      private:
        /** Zeiger auf das Objekt, dessen Methode ausgefuehrt werden soll. */
        TObject* mObject;                 
    
        /** Funktionszeiger auf die Objektmethode */
        PClassCB mMethod ;
    } ;
    
    class TestClassA
    {
      public:
        // Constructor
        TestClassA( void ) {}
    
        // Destructor
        virtual ~TestClassA( void ) throw() {}
    
        // Methode ohne Argument
        void Function0( void )
        {
          mBuffer << "TestClassA: Aufruf ohne Argument" << '\n' ;
        }
    
        // Argumenttyp mit 1 Argument fuer die Methode 'Function1'
        typedef mlib::MFunctorArg1< mlib::MString > Arg1 ;
    
        // Methode mit 1 Argument
        void Function1(
          const Arg1& arg
        )
        {
          mBuffer
            << "TestClassA: "
            << arg.Arg1() << '\n' ;
        }
    
        // Argumenttyp mit 2 Argumenten fuer die Methode 'Function2'
        typedef mlib::MFunctorArg2< mlib::MString, double > Arg2 ;
    
        // Methode mit 2 Argumenten
        void Function2(
          const Arg2& arg
        )
        {
          mBuffer
            << "TestClassA: "
            << arg.Arg1()
            << ": value = " << arg.Arg2()
            << '\n' ;
        }
    
        // Argumenttyp mit 3 Argumenten fuer die Methode 'Function3'
        typedef mlib::MFunctorArg3< mlib::MString, double, bool > Arg3 ;
    
        // Methode mit 3 Argumenten
        void Function3(
          const Arg3& arg
        )
        {
          mBuffer
            << "TestClassA: "
            << arg.Arg1()
            << ": value = " << arg.Arg2()
            << "; state = " << ( arg.Arg3() ? "active" : "inactive" )
            << '\n' ;
        }
    
        // Printmethode zur Ausgabe des Stream-Buffers
        std::ostream& Print(
          std::ostream& os
        )
        {
          os << mBuffer.str() ;
    
          return os ;
        }
    
      protected:
        // Stream-Buffer
        std::stringstream mBuffer ;
    } ;
    
    void MFunctor_Sample(
      std::ostream&        os,
      const mlib::MString& iFileName,
      const mlib::MString& oFileName,
      int                  num,
      int                  argc,
      char**               argv
    )
    {
      os << "1. Aufruf der Methoden von Klasse TestClassA mit Functor-Argumenten\n" << std::endl ;
    
      // Definition der Functor-Datentypen
      typedef mlib::MFunctor0Tmpl< TestClassA > Functor0 ;
    
      // Instanz von 'TestClassA' erzeugen
      TestClassA testA ;
    
      // Methoden von Klasse 'TestClassA' ueber Functor aufrufen
      Functor0( testA, &TestClassA::Function0 ).Execute() ;
    }
    

    hier die fehler

    MFunctor_Example.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) public: virtual __thiscall mlib::MFunctor0Tmpl<class TestClassA>::~MFunctor0Tmpl<class TestClassA>(void)" (__imp_??1?MFunctor0Tmpl@VTestClassA@@@mlib@@UAE@XZ) referenced in function "void \_\_cdecl MFunctor\_Sample(class std::basic\_ostream > &,class mlib::MString const &,class mlib::MString const &,int,int,char * *)" (?MFunctor\_Sample@@YAXAAV?basic_ostream@DU?char_traits@D@std@@@std@@ABVMString@mlib@@1HHPAPAD@Z) MFunctor\_Example.obj : error LNK2019: unresolved external symbol "\_\_declspec(dllimport) public: \_\_thiscall mlib::MFunctor0Tmpl::MFunctor0Tmpl(class TestClassA &,void (\_\_thiscall TestClassA::*)(void))" (\_\_imp\_??0?MFunctor0Tmpl@VTestClassA@@@mlib@@QAE@AAVTestClassA@@P82@AEXXZ@Z) referenced in function "void __cdecl MFunctor_Sample(class std::basic_ostream<char,struct std::char_traits<char> > &,class mlib::MString const &,class mlib::MString const &,int,int,char * *)" (?MFunctor_Sample@@YAXAAV?basic_ostream@DU?basic\_ostream@DU?char_traits@D@std@@@std@@ABVMString@mlib@@1HHPAPAD@Z)


Anmelden zum Antworten