Partage
  • Partager sur Facebook
  • Partager sur Twitter

Accès au constructeur d'une classe

    8 mars 2019 à 12:14:15

    Bonjour à tous,

    Je travaille sur un plugin que je devrais ajouter à un logiciel codé en C++, et je me retrouve bloqué lors du build.

    Je définis un constructeur dans mon code me permettant de créer des variables sur l'ensemble de mon code mais cela ne semble pas être réalisable.

    En effet, le message est le suivant :

     error LNK2005: "public: __thiscall OpenViBEPlugins::SignalProcessing::CBoxAlgorithmVisualInterface::CBoxAlgorithmVisualInterface(void)" (??0CBoxAlgorithmVisualInterface@SignalProcessing@OpenViBEPlugins@@QAE@XZ) dÚjÓ dÚfini(e) dans ovpCBoxAlgorithmVisualInterface.cpp.obj
       CrÚation de la bibliothÞque contrib\plugins\processing\signal-processing\openvibe-plugins-contrib-signal-processing.lib et de l'objet contrib\plugins\processing\signal-processing\openvibe-plugins-contrib-signal-processing.exp
    contrib\plugins\processing\signal-processing\openvibe-plugins-contrib-signal-processing.dll : fatal error LNK1169: un ou plusieurs symboles dÚfinis Ó diffÚrentes reprises ont ÚtÚ rencontrÚs

    Ce qui semble signifier que le constructeur a déjà été défini (il doit être créé par défaut), y'a t-il un moyen de contourner le constructeur mais de quand même définir des variables globales ?

    Merci beaucoup,

    Tristan

    • Partager sur Facebook
    • Partager sur Twitter
      8 mars 2019 à 13:10:22

      Salut,

      L'erreur que tu nous montre est émise par ce que l'on appelle l'éditeur de liens.

      En gros, c'est l'outil qui va s'occuper de regrouper tous les fichiers objets (*.obj / *.o, selon le compilateur) généré par le compilateur et contenant le code binaire exécutable par le processeur à partir du code (C++) que tu as écrit en un fichier exécutable unique.

      Cet outil va, entre autres, s'assurer que les différents appels aux différentes fonctions "pointeront" bien vers l'adresse mémoire à laquelle les fonctions en question se trouvent dans l'exécutable final.

      Mais, pour cela, il doit aussi s'assurer que le code binaire exécutable de chaque fonction n'existe qu'une seule et unique fois dans l'exécutable (sauf pour ce qui est des fonctions inline).

      Si, pour une raison ou une autre, l'éditeur de liens trouve deux fois le code binaire exécutable de la même fonction dans les différents fichiers objets, il se retrouve dans l'impossibilité de choisir entre les deux implémentation lorsqu'il doit indiquer l'adresse mémoire de la fonction, et il n'a donc pas d'autre choix que de s'arrêter après t'avoir engueulé (en présentant cette erreur).

      La raison de cette erreur est "simple à comprendre", dans le sens où elle se produit quand le code correspondant à une fonction (de toute évidence, il s'agit de la fonction CBoxAlgorithmVisualInterface::CBoxAlgorithmVisualInterface() apparaît dans plusieurs fichier *.cpp.

      Le principe pour corriger cette erreur est, finalement, tout aussi simple, dans le sens où "il suffit" de s'assurer que le code de cette fonction n’apparaîtra que dans un seul fichier *.cpp.

      Mais, pour effectivement pouvoir corriger ce problème, il va falloir chercher, dans les différents fichiers *.cpp, tous ceux qui fournissent l'implémentation de cette fonction, puis, il faudra choisir quelle implémentation on veut garder, et, enfin, il faudra supprimer toutes les autres.  Et ca, ca risque d'être un peu plus difficile.

      Enfin, nous aurions sans doute beaucoup plus facile à t'aider si tu nous proposais un peu de code pour repérer l'erreur ;)

      • Partager sur Facebook
      • Partager sur Twitter
      Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
        8 mars 2019 à 13:52:17

        Bonjour,

        Merci pour cette réponse très détaillée, je comprends mieux ce .cpp.obj, ce que je n'arrive pas à comprendre c'est que je viens de créer le plugin, il ne devrait pas y avoir d'autres endroits où pourrait être le constructeur.

          Ce dernier est créé sans doute par défaut lors de la génération du "squelette du code" (un logiciel qui permet de donner la bonne architecture au départ), j'ai sans doute un autre endroit où celui -ci ce retrouve initialisé.

        Voici le cpp et le .h :

        #include <iostream>
        #include <fstream>
        #include <cstdlib>
        
        #include <sys/timeb.h>
        
        #include <tcptagging/IStimulusSender.h>
        
        namespace OpenViBEPlugins {
        
        	namespace SignalProcessing
        	{
        
        		gboolean VisualInterface_SizeAllocateCallback(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
        		{
        			reinterpret_cast<CBoxAlgorithmVisualInterface*>(data)->resize((uint32)allocation->width, (uint32)allocation->height);
        			return FALSE;
        		}
        
        		gboolean VisualInterface_RedrawCallback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
        		{
        			reinterpret_cast<CBoxAlgorithmVisualInterface*>(data)->redraw();
        			return TRUE;
        		}
        
        		CBoxAlgorithmVisualInterface::CBoxAlgorithmVisualInterface(void) :
        		
        			
        			m_pBuilderInterface(NULL),
        			m_pMainWindow(NULL),
        			m_pDrawingArea(NULL),
        
        
        			m_visualizationContext(nullptr)
        		{
        			m_oBackgroundColor.pixel = 0;
        			m_oBackgroundColor.red = 0;
        			m_oBackgroundColor.green = 0;
        			m_oBackgroundColor.blue = 0;
        
        			m_oForegroundColor.pixel = 0;
        			m_oForegroundColor.red = 0xFFFF;
        			m_oForegroundColor.green = 0xFFFF;
        			m_oForegroundColor.blue = 0xFFFF;
        		}
        
        		bool CBoxAlgorithmVisualInterface::initialize(void)
        		{
        			m_oInput0Decoder.initialize(*this, 0);
        			m_oInput1Decoder.initialize(*this, 1);
        
        
        
        			return true;
        		}
        		/*******************************************************************************/
        
        		bool CBoxAlgorithmVisualInterface::uninitialize(void)
        		{
        			m_oInput0Decoder.uninitialize();
        			m_oInput1Decoder.uninitialize();
        
        
        			return true;
        		}
        		/*******************************************************************************/
        
        
        
        
        		bool CBoxAlgorithmVisualInterface::process(void)
        		{
        
        			// the static box context describes the box inputs, outputs, settings structures
        			const IBox& l_rStaticBoxContext = this->getStaticBoxContext();
        			// the dynamic box context describes the current state of the box inputs and outputs (i.e. the chunks)
        			IBoxIO& l_rDynamicBoxContext = this->getDynamicBoxContext();
        
        
        
        
        			// Tutorials:
        			// http://openvibe.inria.fr/documentation/#Developer+Documentation
        			// Codec Toolkit page :
        			// http://openvibe.inria.fr/codec-toolkit-references/
        
        			// Feel free to ask experienced developers on the forum (http://openvibe.inria.fr/forum) and IRC (#openvibe on irc.freenode.net).
        
        			return true;
        		}
        		void CBoxAlgorithmVisualInterface::resize(uint32 ui32Width, uint32 ui32Height){}
        
        		void CBoxAlgorithmVisualInterface::redraw(){}
        
        		void CBoxAlgorithmVisualInterface::activate()
        		{
        			char buffer[100];
        			int retVal;
        			char name[] = "Max";
        			int age = 23;
        
        			retVal = sprintf(buffer, "Hi, I am %s and I am %d years old", name, age);
        
        			//gint speedX = m_pDrawingArea->allocation.width;
        
        		}
        	};
        };

        #ifndef __OpenViBEPlugins_BoxAlgorithm_VisualInterface_H__
        #define __OpenViBEPlugins_BoxAlgorithm_VisualInterface_H__
        
        //You may have to change this path to match your folder organisation
        #include "../ovp_defines.h"
        
        #include <openvibe/ov_all.h>
        #include <toolkit/ovtk_all.h>
        
        
        #include <visualization-toolkit/ovviz_all.h>
        
        #include <gtk/gtk.h>
        
        #include <vector>
        #include <string>
        #include <map>
        #include <deque>
        
        
        // The unique identifiers for the box and its descriptor.
        // Identifier are randomly chosen by the skeleton-generator.
        #define OVP_ClassId_BoxAlgorithm_VisualInterface (0x9043ece1, 0xc2dc5b71)
        #define OVP_ClassId_BoxAlgorithm_VisualInterfaceDesc (0xad428a6b, 0xa842ddd6)
        #define OV_AttributeId_Box_FlagIsUnstable OpenViBE::CIdentifier(0x666FFFFF, 0x666FFFFF)
        
        namespace TCPTagging
        {
        	class IStimulusSender; // fwd declare
        };
        namespace OpenViBEPlugins
        {
        	namespace SignalProcessing
        	{
        		/**
        		* \class CBoxAlgorithmVisualInterface
        		* \author Tristan (Sorbonne Université)
        		* \date Tue Feb 12 14:49:06 2019
        		* \brief The class CBoxAlgorithmVisualInterface describes the box VisualInterface.
        		*
        		*/
        		class CBoxAlgorithmVisualInterface : virtual public OpenViBEToolkit::TBoxAlgorithm < OpenViBE::Plugins::IBoxAlgorithm >
        		{
        		public:
        
        			CBoxAlgorithmVisualInterface();
        
        			virtual void release(void) { delete this; }
        
        			virtual bool initialize(void);
        			virtual bool uninitialize(void);
        
        			//Here is the different process callbacks possible
        			// - On clock ticks :
        			//virtual bool processClock(OpenViBE::CMessageClock& rMessageClock);		
        			// - On new input received (the most common behaviour for signal processing) :
        			//virtual bool processInput(uint32_t ui32InputIndex);
        
        			// If you want to use processClock, you must provide the clock frequency.
        			//virtual uint64_t getClockFrequency(void);
        
        			virtual bool process(void);
        			virtual void redraw();
        			virtual void activate();
        			virtual void resize(OpenViBE::uint32 ui32Width, OpenViBE::uint32 ui32Height);
        
        			// Variables used for the motion of the ball.
        
        
        
        
        			// As we do with any class in openvibe, we use the macro below 
        			// to associate this box to an unique identifier. 
        			// The inheritance information is also made available, 
        			// as we provide the superclass OpenViBEToolkit::TBoxAlgorithm < OpenViBE::Plugins::IBoxAlgorithm >
        			_IsDerivedFromClass_Final_(OpenViBEToolkit::TBoxAlgorithm < OpenViBE::Plugins::IBoxAlgorithm >, OVP_ClassId_BoxAlgorithm_VisualInterface);
        
        		protected:
        			// Input decoder:
        			OpenViBEToolkit::TStimulationDecoder < CBoxAlgorithmVisualInterface > m_oInput0Decoder;
        			OpenViBEToolkit::TStreamedMatrixDecoder < CBoxAlgorithmVisualInterface > m_oInput1Decoder;
        			// No Output decoder.
        
        			//The Builder handler used to create the interface
        			::GtkBuilder* m_pBuilderInterface;
        			::GtkWidget*  m_pMainWindow;
        			::GtkWidget*  m_pDrawingArea;
        
        
        
        
        			::GdkColor m_oBackgroundColor;
        			::GdkColor m_oForegroundColor;
        			
        
        
        
        
        		private:
        			OpenViBEVisualizationToolkit::IVisualizationContext* m_visualizationContext = nullptr;
        
        
        		};
        
        
        		// If you need to implement a box Listener, here is a skeleton for you.
        		// Use only the callbacks you need.
        		// For example, if your box has a variable number of input, but all of them must be stimulation inputs.
        		// The following listener callback will ensure that any newly added input is stimulations :
        		/*
        		virtual bool onInputAdded(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index)
        		{
        		rBox.setInputType(ui32Index, OV_TypeId_Stimulations);
        		};
        		*/
        
        		/*
        		// The box listener can be used to call specific callbacks whenever the box structure changes : input added, name changed, etc.
        		// Please uncomment below the callbacks you want to use.
        		class CBoxAlgorithmVisualInterfaceListener : public OpenViBEToolkit::TBoxListener < OpenViBE::Plugins::IBoxListener >
        		{
        		public:
        
        		//virtual bool onInitialized(OpenViBE::Kernel::IBox& rBox) { return true; };
        		//virtual bool onNameChanged(OpenViBE::Kernel::IBox& rBox) { return true; };
        		//virtual bool onInputConnected(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onInputDisconnected(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onInputAdded(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onInputRemoved(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onInputTypeChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onInputNameChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onOutputConnected(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onOutputDisconnected(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onOutputAdded(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onOutputRemoved(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onOutputTypeChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onOutputNameChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onSettingAdded(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onSettingRemoved(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onSettingTypeChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onSettingNameChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onSettingDefaultValueChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        		//virtual bool onSettingValueChanged(OpenViBE::Kernel::IBox& rBox, const uint32_t ui32Index) { return true; };
        
        		_IsDerivedFromClass_Final_(OpenViBEToolkit::TBoxListener < OpenViBE::Plugins::IBoxListener >, OV_UndefinedIdentifier);
        		};
        		*/
        
        		/**
        		* \class CBoxAlgorithmVisualInterfaceDesc
        		* \author Tristan (Sorbonne Université)
        		* \date Tue Feb 12 14:49:06 2019
        		* \brief Descriptor of the box VisualInterface.
        		*
        		*/
        		class CBoxAlgorithmVisualInterfaceDesc : virtual public OpenViBE::Plugins::IBoxAlgorithmDesc
        		{
        		public:
        
        			virtual void release(void) { }
        
        			virtual OpenViBE::CString getName(void) const                { return OpenViBE::CString("VisualInterface"); }
        			virtual OpenViBE::CString getAuthorName(void) const          { return OpenViBE::CString("Tristan"); }
        			virtual OpenViBE::CString getAuthorCompanyName(void) const   { return OpenViBE::CString("Sorbonne Université"); }
        			virtual OpenViBE::CString getShortDescription(void) const    { return OpenViBE::CString("Ball controlled by thoughts"); }
        			virtual OpenViBE::CString getDetailedDescription(void) const { return OpenViBE::CString("Control of the ball due to the detection of a cortex activity"); }
        			virtual OpenViBE::CString getCategory(void) const            { return OpenViBE::CString("Signal processing"); }
        			virtual OpenViBE::CString getVersion(void) const             { return OpenViBE::CString("1.0"); }
        			virtual OpenViBE::CString getStockItemName(void) const       { return OpenViBE::CString("gtk-fullscreen"); }
        
        			virtual OpenViBE::CIdentifier getCreatedClass(void) const    { return OVP_ClassId_BoxAlgorithm_VisualInterface; }
        			virtual OpenViBE::Plugins::IPluginObject* create(void)       { return new OpenViBEPlugins::SignalProcessing::CBoxAlgorithmVisualInterface; }
        
        			/*
        			virtual OpenViBE::Plugins::IBoxListener* createBoxListener(void) const               { return new CBoxAlgorithmVisualInterfaceListener; }
        			virtual void releaseBoxListener(OpenViBE::Plugins::IBoxListener* pBoxListener) const { delete pBoxListener; }
        			*/
        			virtual bool getBoxPrototype(
        				OpenViBE::Kernel::IBoxProto& rBoxAlgorithmPrototype) const
        			{
        				rBoxAlgorithmPrototype.addInput("Stimulations", OV_TypeId_Stimulations);
        				rBoxAlgorithmPrototype.addInput("Ampltude", OV_TypeId_StreamedMatrix);
        
        				rBoxAlgorithmPrototype.addFlag(OpenViBE::Kernel::BoxFlag_CanModifyInput);
        				rBoxAlgorithmPrototype.addFlag(OpenViBE::Kernel::BoxFlag_CanAddInput);
        
        				//No output specified.To add outputs use :
        				//rBoxAlgorithmPrototype.addOutput("OutputName",OV_TypeId_XXXX);
        
        				//rBoxAlgorithmPrototype.addFlag(OpenViBE::Kernel::BoxFlag_CanModifyOutput);
        				//rBoxAlgorithmPrototype.addFlag(OpenViBE::Kernel::BoxFlag_CanAddOutput);
        
        				rBoxAlgorithmPrototype.addSetting("Show instruction", OV_TypeId_Boolean, "true");
        				rBoxAlgorithmPrototype.addSetting("Show feedback", OV_TypeId_Boolean, "false");
        				rBoxAlgorithmPrototype.addSetting("Delay feedback", OV_TypeId_Boolean, "false");
        				rBoxAlgorithmPrototype.addSetting("Show accuracy", OV_TypeId_Boolean, "false");
        				rBoxAlgorithmPrototype.addSetting("Predictions to integrate", OV_TypeId_Integer, "5");
        				rBoxAlgorithmPrototype.addSetting("Positive feedback only", OV_TypeId_Boolean, "false");
        
        				rBoxAlgorithmPrototype.addFlag(OpenViBE::Kernel::BoxFlag_CanModifySetting);
        				rBoxAlgorithmPrototype.addFlag(OpenViBE::Kernel::BoxFlag_CanAddSetting);
        
        				rBoxAlgorithmPrototype.addFlag(OV_AttributeId_Box_FlagIsUnstable);
        
        				return true;
        			}
        			_IsDerivedFromClass_Final_(OpenViBE::Plugins::IBoxAlgorithmDesc, OVP_ClassId_BoxAlgorithm_VisualInterfaceDesc);
        		};
        	};
        };
        
        #endif // __OpenViBEPlugins_BoxAlgorithm_VisualInterface_H__





        -
        Edité par TristanVENOT 8 mars 2019 à 13:53:31

        • Partager sur Facebook
        • Partager sur Twitter
          8 mars 2019 à 22:36:46

          Es tu sur de n'avoir inclus ton fichier *.cpp nulle part?

          Faire un

          #include <mon_fichier.cpp>

          au lieu de faire un

          #include <mon_fichier.hpp>

          c'est vite arrivé :p:-°:waw:


          • Partager sur Facebook
          • Partager sur Twitter
          Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
            13 mars 2019 à 12:03:26

            Bonjour,

            Non le problème ne venait malheuresement pas de là mais il est à présent réglé même si l'explication que je me suis donné ne me satisfait pas entièrement.

            Merci quand même,

            Tristan Venot

            • Partager sur Facebook
            • Partager sur Twitter
              13 mars 2019 à 14:42:45

              Il serait peut-être intéressant de nous fournir cette "erreur" et cette "explication".
              • Partager sur Facebook
              • Partager sur Twitter
              Didy7 -
                14 mars 2019 à 11:53:11

                Le logiciel a une fonction permettant d'ajouter un plugin, cette fonction crée un fichier .cpp et un fichier .h prérempli et qui possède un constructeur par défaut. lorsque l'on écrit dans le .cpp un constructeur, lors du build, le programme ne sait pas s'il doit prendre le constructeur par défaut ou le constructeur modifié. Cependant, on ne peut pas accéder au constructeur par défaut car cela dépend de la fonction du logiciel qui doit sans doute instaurer que le constructeur ne peut pas être modifié. Ma solution a été de créer le plugin manuellement en ne passant pas par le logiciel, ainsi lors du build, le constructeur pris en compte était celui de mon code et non celui créé par défaut.

                Dites moi ce que vous en penser,

                Tristan

                • Partager sur Facebook
                • Partager sur Twitter
                  14 mars 2019 à 14:18:17

                  >Dites moi ce que vous en penser,

                  Que vous devriez arrêter la fumette et penser à utiliser le rasoir d’Ockham.

                  C'est juste que les concepteurs du logiciel ont instauré qu'ils n'utiliseraient que le constructeur par défaut.

                  >qui doit sans doute instaurer que le constructeur ne peut pas être modifié

                  Why ??

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                    17 mars 2019 à 18:35:44

                    Vous semblez bien sûr de vous pour quelqu'un qui n'a aucune idée du logiciel dont je parle,

                    Pourquoi le constructeur ne peut pas être modifier ?

                    Parce que la façon de créer un plugin en passant par une fonction du logiciel n'est pas pensé pour le faire.

                    Et c'est idiot de penser que les concepteurs "ont instauré qu'ils n'utiliseraient que le constructeur par défaut", en effet le logiciel est opensource et est utilisé dans un but de recherche, donc de nombreux contributeurs créent leur propre plugin pour enrichir le logiciel de base, ils ajoutent donc un constructeur.

                    • Partager sur Facebook
                    • Partager sur Twitter
                      17 mars 2019 à 19:11:26

                      Parce que c'est un plugin, celui qui a écrit le logiciel qui va utiliser ton plugin ne peut pas deviner la signature de ton constructeur, il n'a pas d'autre choix que d'assumer que ta classe lui fournira un constructeur compatible avec ce qu'il peut gérer (ici un constructeur par défaut).
                      • Partager sur Facebook
                      • Partager sur Twitter
                      Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug

                      Accès au constructeur d'une classe

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      • Editeur
                      • Markdown