Partage
  • Partager sur Facebook
  • Partager sur Twitter

[C++/CL] utiliser des variables partout!

Utiliser une variable de type string en global dans un .h ??

    22 septembre 2018 à 15:23:59

    Bonjour/Bonsoir,

    je viens de commencer un petit projet sur Visual Studio, le problème étant, que je souhaite avoir accès à plusieurs variables de type string créer et initialisé dans MyForm_Load! J'aimerais pouvoir les utiliser dans button1_click par exemple.. Je n'arrive pas à trouver malgré quelques recherches (Je n'ai sans doute pas cherché correctement) J'aimerais avoir des explications si possible. Un grand merci d'avance. Je viens de commencer le c++, je connais très bien le c. Le principe de class etc me perturbe pas mal...

    Voici le bout de code en question. J'aimerais avoir accès string dans button1_click. Merci.

    #pragma endregion
    
    	private: System::Void MyForm_Load(System::Object^  sender, System::EventArgs^  e)
    	{
    		string username;
    		string osVersion;
    		string systemType;
    		string serialNumber;
    
    		// GET INFO
    		system("echo %username% >> systeminfo");
    		system("wmic os get caption | findstr Win >> systeminfo");
    		system("wmic os get serialnumber | findstr \"0 1 2 3 4 5 6 7 8 9\" >> systeminfo");
    		system("wmic OS get OSArchitecture | findstr bits >> systeminfo");
    
    		// OPEN FILE
    		ifstream file("systeminfo"); // Open the file
    
    		if (file)
    		{
    			getline(file, username);
    			getline(file, osVersion);
    			getline(file, serialNumber);
    			getline(file, systemType);
    
    			file.close();
    			remove("systeminfo");
    		}
    		else
    		{
    			cerr << "Error opening file" << endl;
    		}
    		// END FILE
    
    		// DISPLAY INFO
    		user_label->Text = gcnew String(username.c_str());
    		os_label->Text = gcnew String(osVersion.c_str());
    		id_label->Text = gcnew String(serialNumber.c_str());
    		systemt_label->Text = gcnew String(systemType.c_str());
    	}
    	private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) 
    	{
    		if (username == "") ????????????????
    			Application::Exit();
    	}
    };
    }
    



    -
    Edité par Frozziak 22 septembre 2018 à 15:27:34

    • Partager sur Facebook
    • Partager sur Twitter
      22 septembre 2018 à 18:05:11

      Salut,

      Avant de t'intéresser à C++/cli, tu devrais peut être commencer par t'assurer de comprendre les principes que C++ (non cli) ajoute au C ;)... Cela pourrait te simplifier la vie ;)

      Mais bon, le principe des classes en C++ est très semblable au principe des structures en C :

      Ce sont des agrégations de données. La grosse différence qui nous intéresse dans un premier temps entre les deux, c'est que l'on peut fournir ce que l'on appelle des fonctions membres (on parle parfois de "méthode" dans les autres langages, mais l'acception de ce terme fait que l'on n'en parlera en C++ que pour désigner certaines fonctions membre seulement) à notre agrégat de donnée.

      Le principe de ces fonctions membres est "relativement simple": ce sont des fonctions auxquelles nous ne pourront faire appel que depuis une instance existante (faisons simple : une variable du type) de l'agrégat.

      Pour faire très simple, cela revient à créer une fonction qui prendra un pointeur sur la variable au départ de laquelle la fonction est appelée.  Si on a un agrégat nommé MyStruct, et qu'on lui adjoint la fonction foo, cela reviendrait en C à créer une fonction proche de

      typeDeRetour foo(struct MyStruct * this /*, autres paramètres nécessaire)

      Cette fonction peut donc accéder à ... toutes les données qui composent l'agrégat de donnée (la structure MyStruct, dans le cas présent)

      La deuxième différence qui nous intéresse dans le cas présent, c'est que l'on peut préciser ce que l'on appelle l'accessibilité (des données et des fonctions membre) de notre agrégat de données.

      Cette notion permet de préciser -- continuons à faire simple -- "qui peut accéder à quel élément de notre agrégat" (données et fonctions membres confondues).

      Il existe trois niveau d'accessibilité. Du moins permissif au plus permissif, il s'agit de :

      • private: il n'y a que les fonctions membres de notre agrégat qui peuvent accéder au éléments de notre agrégat qui se trouvent dans ce niveau d'accessibilité
      • protected: je ne vais pas en parler ici et
      • public: n'importe qui peut accédeer aux élément de notre agrégat qui se trouvent dans ce niveau d'accessibilité, y compris les fonction qui n'en font pas partie.

      Pour être tout à fait complet, il existe une dernière différence entre C et C++ : on peut définir ce que l'on appelle une relation d'héritage entre deux agrégats de données. 

      Mais, comme cela n'apportera pas grand chose à la compréhension, et que mon intervention prévoit déjà d'être très longue, je n'en parlerai pais ici (par simplicité ;) )

      Les deux différences que j'ai pris la peine d'expliquer font qu'il est toujours préférable de changer la manière dont on va réfléchir à nos agrégats de données.

      Car, comme on peut "cacher" des éléments de notre agrégat à "ce qui n'en fait pas partie", et que nous pouvons faire appel à des fonctions qui seront systématiquement appelées depuis une instance de notre agrégat, il devient particulièrement intéressant de considérer notre classe ou notre structure plus comme un "fournisseur de service" que comme... un agrégat de données.

      L'idée est -- encore une fois -- "relativement simple" (à expliquer, du moins): Au lieu de se dire que "notre classe (ou notre structure) doit contenir telle et telle donnée de tel et tel type", on va réfléchir à "quelles sont les ordres que je veux pouvoir lui donner?" et à "quelles sont les questions que je veux pouvoir lui poser?".

      Cela nous permettra de dresser la liste des fonctions membres que nous placerons dans l'accessibilité publique et ... de définir les données qui permettront à ces fonctions de "faire leur job" dans l'accessibilité privée, selon le principe qu'il faut

      faire en sorte que les données soient simples à utiliser correctement et difficile à utiliser de manière incorrecte

      Ce principe n'est -- en réalité -- qu'une variation sur le thème de la loi de Déméter, et tu remarqueras d'ailleurs qu'il a été amplement mis en oeuvre en C.

      L'exemple le plus frappant que j'aie en tête est la structure FILE: on ne sait pas et on n'a absolument pas à savoir de quelles données cette structure est composée.  Par contre, la bibliothèque standard du C nous propose "un certain nombre" de fonctions qui nous permettent de l'utiliser correctement et qui "limite le risque d'utilisation incorrecte" (fopen, fread, fwrite, et toutes les autres).

      L'idée est donc de généraliser le plus possible cette approche, parce que tu connaît le principe: 100% des bug sont provoqués par l'interface entre la chaise et le clavier :D

      Je vais te laisser digérer cette intervention, qui, je l'espère, devrait te "mettre sur la voie" pour résoudre ton problème.

      Si ce n'est pas le cas, reviens vers nous, et nous essayerons de réfléchir ensemble à "comment t'y prendre" ;)

      • 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
        22 septembre 2018 à 19:08:05

        Merci beaucoup koala01 pour cette réponse complète et détaillée!

        En effet, j'ai peut être voulu me lancer un peu rapidement sur ce projet... à la base je voulais réaliser mon programme en C ! Mais je n'ai pas trouvé une façon agréable de réaliser une interface graphique en C...

        Donc, d’après ce que j'ai compris ; En gros, mes variables se trouve dans une structure ? Je devrais donc mettre, dans mon exemple : 

        MyForm_Load->username ???

        Je suis preneur si vous avez des tutoriaux vidéo ou écrit a ce sujet ?? 

        En tout cas merci d'avoir pris le temps de me répondre.
         

        -
        Edité par Frozziak 22 septembre 2018 à 19:09:15

        • Partager sur Facebook
        • Partager sur Twitter
          22 septembre 2018 à 20:29:17

          Disons que, là où, en C, tu aurais sans doute un code proche de
          struct MyStruct{
              Type1 data1;
              Type2 data2;
          };
          void foo(struct MyStruct * this){
              this->data1 = /* n'importe quoi, vu qu'on ne sait pas
                             * ce que cela représente
                             */
          }
          void bar(struct MyStruct * this/* autres paramètres*/){
              this->data2 = /* n'importe quoi, vu qu'on ne sait pas
                             * ce que cela représente
                             */
          
          }
          struct MyStruct * createStruct(/* paramètres requis */){
               MyStruct temp = malloc(sizeof(MyStruct));
               if(! temp){
                   printf("unable to create element");
                   exit(EXIT_FAILURE);
               }
               /* tout ce qu'il faut pour initialiser data1 et data2 */
               return temp;
          }
          void destroyStruct(struct MyStruct * ptr){
              /* ... on détruit les données membres "comme il faut"
               * puis on libère la mémoire associée à ptr
               */
              free(ptr);
          }

          et qui serait sans doute utilisé sous une forme proche de

          int main(){
              struct Mystruct obj;
              foo(&obj);
              bar(&obj/*, autres arguments*/);
              /* OU OU OU */
              struct MyStruct * ptr = createStruct(/* ... */);
              if(ptr){
                  foo(ptr);
                  bar(ptr/*, ...*/);
                  /* ...*/
                  destroyStruct(ptr);
              }
          }

          tu pourrais avoir, en C++, quelque chose qui serait proche de

          class Myclass{ // note que cela fonctionne aussi avec le mot clé
                         // struct (*)
          public:
              /* ceci s'appelle un "constructeur"...
               * son but est somme toute identique à la fonction createStruct 
               */
              MyClass(/* paramètres requis*/);
              /* ceci s'appelle un "destructeur"...
               * son but est somme toute identique à la fonction destroyStruct 
               */
              ~MyClass;
              void foo();
              void bar(/* paramètres requis */)
          private:
              Type1 data1;
              Type2 data2;
          };

          Pour fournir l'implémentation des différentes fonction, tu pourrais les placer directement dans la déclaration de MyClass, ce qui les rendrait automatiquement inline, ou tu peux (c'est préférable dans bien des cas) fournir une implémentation séparée.  Tu dois alors utiliser le "nom pleinement qualifié" de la fonction (c'est le nom qui contient également le nom de la classe pour éviter toute ambiguité), sous une forme proche de

          MyClass::MyClass(/* paramètres requis){ //(*)
             /* ce qui doit être fait pour créer l'objet*/
          }
          MyClass::~MyClass(){ // (*)
             /* ce qui doit être fait pour détruire correctement
              * l'objet
              */
          }
          void MyClass::foo(){
              /* ce qui doit être fait...
               * on peut accéder directement à
               * data1 d'ici dedans
               */
          }
          void MyClass::bar(/* paramètres requis*/){
              /* ce qui doit être fait...
               * on peut accéder directement à
               * data2 d'ici dedans
               */
          }

          (*) note que le constructeur et le destructeur sont des fonctions "particulières" à plus d'un titre, pour l'instant, contentons nous de savoir que l'une des particularité est qu'elle n'ont pas besoin du type de retour ;)

          et tu pourrais utiliser tout cela sous une forme proche de

          int main(){
              MyClass obj{/* arguments nécessaires}; // (*)
              obj.foo(); // invoque la fonction MyClass::foo() depuis
                         // l'objet obj
              obj.foo(/*... */); // invoque la fonction MyClass::bar() depuis
                         // l'objet obj
          } //(**)

          (*) j'utilise ici une syntaxe apparue en C++11.  Elle fait appel au constructeur de MyClass

          (**) Quand on quitte la portée dans laquelle une donnée (pour laquelle on n'a pas eu recours à l'allocation dynamique) est déclarée, le destructeur est de la donnée est automatiquement appelé.

          Peut-être ses explications t'aideront-elle à comprendre un peu mieux ce que tu dois faire??

          NOTA : System est ce que l'on appelle un espace de noms (un namespace en anglais). Pour faire simple, c'est une sorte de boite dans laquelle nous pourrons ranger "tout ce qui va bien ensemble" ou qui "s'intègre à un module particulier". 

          Dans le cas présent, System représente la boite dans laquelle C++/cli placera ... tout ce qui a trait au système (merci lapalisse :D )

          Si tu veux que les différentes fonctions membres d'une de tes classes puisse "partager" le traitement de différentes données, tu devras déclarer ces données en tant que données membres de la classe en question (à moins que ce ne soit des "données externes"... Tu devrais alors les transmettre comme paramètre aux fonction, comme toute données "impossible à calculer par la fonction elle-même")

          • 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
            22 septembre 2018 à 21:01:59

            Je comprends tes explications au niveau C, je vois un petit peu le développement ; la logique. Je dois donc faire passer mes variables en paramètre? ou je peux faire une class pour mes variables et ensuite faire un appel de la classe quand j'en ai besoin ? ahhh je vais devenir fou, c'est surement tout bête une fois compris je suppose... Je sais que c'est pas la bonne méthode pour comprendre mais j'aurais sans doute besoin de la résolution du problème pour analyser et comprendre. Car le problème est, que en C j'aurais fait complètement différent et j'aurais pas utilisé de structure. Il faut dire que les interfaces graphique c'est nouveau aussi pour moi. Merci beaucoup pour ton aide.
            • Partager sur Facebook
            • Partager sur Twitter
              22 septembre 2018 à 21:14:07

              private: System::Void MyForm_Load(System::Object^  sender, System::EventArgs^  e)

               Je comprends pas les paramètres de la fonction ici ? C'est comme le foo et bar ? 

              J'ai déjà essayé de faire passer mes variables en pointeurs mais après je sais plus les utiliser pour initialiser les label->Text  

              -
              Edité par Frozziak 22 septembre 2018 à 21:17:22

              • Partager sur Facebook
              • Partager sur Twitter
                23 septembre 2018 à 16:47:09

                Frozziak a écrit:

                private: System::Void MyForm_Load(System::Object^  sender, System::EventArgs^  e)

                En C++/cli, le symbole ^ représente un "pointeur managé" (autrement dit, un élément dont la durée de vie est gérée par le "ramasse miettes").

                • le parametre sender représente l'élément (graphique le plus souvent) qui aura provoqué l'exécution de la fonction et
                • le paramètre e représente l'ensemble des paramètres qui auront été transmis par sender à la fonction

                De manière générale, nous sommes dans un cas typique d'utilisation du patron de conceptions observateur, MyForm_load étant -- a priori -- exécuté soit directement suite à un "événement" occasionné par un élément graphique (comme le clique sur un bouton, ou le "time out" d'un timer, ... ou autre), soit de manière indirecte, parce qu'une fonction qui a réagit à un événement voudra y faire appel.

                Dans le cas d'un "appel indirect", il peut être intéressant de transmettre l'élément qui aura provoqué l'appel à la fonction appelante ainsi que les paramètres transmis.

                Comme la fonction est marquée private, on peut se dire que, soit l'élément graphique en question qui fait appel à cette fonction fait partie du formulaire MyForm, soit elle est appelée de manière indirecte.  Mais seul le code complet de ton formulaire pourrait nous permettre d'en savoir plus.

                Cependant, comme je présume que tu n'auras pas pensé par toi-même ni à mettre cette fonction dans l'accessibilité privée, ni à fournir ce genre de paramètres, je crois que l'on peut en déduire qu'il s'agit d'une fonction dont le prototype  a été généré automatiquement par ton EDI quand tu as voulu définir le comportement à appliquer lors du clique d'un bouton nommé "Load", et que ce bouton fait partie du formulaire MyForme.

                Me trompai-je??

                • 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
                  24 septembre 2018 à 12:47:49

                  Après que @koala01 se soit chargé des aspects C++, je vais en mettre une couche sur les aspects Windows et .NET. :pirate:

                  - Primo, les librairies C pour faire des IHM, c'est pas ça qui manque, l'API Win32/GDI sous Windows est même la base de toutes les autres ( sauf DirectX, et encore). Pour les IHM portables (et des API plus modernes), je pense que d'autres sur le forum C (pas C++) pourraient t'en fournir des caisses entières.

                  - Secondo, des librairies graphique C++ "standard", c'est pas ce qui manque n'ont plus : MFC, Qt , etc... . Ça ferait quand même une marche d'apprentissage moins rude le "C++" + programmation évènementiel + .NET.

                  - Tertio, votre code ressemble plus à du code d'administrateur système essayant de faire du développement qu'à du code fait par un programmeur système. Pourquoi ? L'usage immodéré de l'API "system", qui est à prescrire de tout code un temps soit peu sérieux.

                  Quitte à utilser WMI, utilisez son API et pas une pauvre application console DOS qui n'est pas faites pour.

                  https://docs.microsoft.com/en-us/windows/desktop/wmisdk/creating-a-wmi-application-using-c-

                  et quitte à utiliser .NET utiliser l'API managée qui va avec :

                  https://msdn.microsoft.com/library/microsoft.management.infrastructure.aspx

                  - Quarto : Le déclenchement de l'event "Load" d'un formulaire n'arrive qu'une fois, quand les contrôles créés dans le constructeur et les fenêtres Kernel associées au formulaire et à ces contrôles visibles ont déjà été créés mais juste avant le premier affichage. Les paramètres de la méthode permettent d'identifier la source de l'évènement car cette méthode peut être enregistrée sur plusieurs sources d'évènements (de type potentiellement différents).

                  - Quinto : Il faudrait architecturer un peu plus la solution, pour que les informations et méthodes de récupération des données n'ait aucun rapport avec l'IHM, permettant d'en changer sans toucher au code métier.

                  - Sixto : Pas besoin de faire des pieds et de mains pour avoir cette info de n'importe où dans ton code :

                  https://docs.microsoft.com/en-us/dotnet/api/system.environment.username?view=netframework-4.7.2

                  - Septo : Pour ta question initiale, et sans faire le refactoting suggérer en "Quinto", le plus simple, c'est de faire de "username" un champ public de ta classe de formulaire, et de caster le résultat de FindForm dans le type ton formulaire :

                  https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.findform?view=netframework-4.7.2#System_Windows_Forms_Control_FindForm

                  Le champ (ou la propriété si tu sais faire) sera directement accessible.

                  (oui, c'est cracra mais c'est simple et ça réduit les embrouilles avec de Designer Graphique)

                  • Partager sur Facebook
                  • Partager sur Twitter
                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                    25 septembre 2018 à 23:16:19

                    Bonjour, merci pour toutes ces informations! Je pense que je vais chercher d'abord a faire de la progra en GUI en C.
                    • Partager sur Facebook
                    • Partager sur Twitter
                      26 septembre 2018 à 1:44:31

                      Frozziak a écrit:

                      Bonjour, merci pour toutes ces informations! Je pense que je vais chercher d'abord a faire de la progra en GUI en C.

                      Si tu veux faire du C++ / si tu as besoin de C++, ne perds pas ton temps à cela...

                      Commences, d'abord et avant tout, par assimiler les base du C++, si c'est du C++ que tu veux faire / dont tu as besoin.

                      Ensuite, à moins que tu n'aies d'excellentes raisons de t'intéresser à C++/cli, si tu as besoin d'une bibliothèque IHM qui puisse fonctionner avec C++, choisi en une qui ... soit écrite en C++  et qui puisse t'offrir:

                      • une documentation correcte et à jour
                      • (si possible) un grand nombre de ressources (aides et tutoriels, bouquins, autres)  pour pouvoir "y regarder à ton aise"
                      • des corrections / mises à jours / nouvelles fonctionnalités régulières
                      • une (grande) communauté réactive et prête à t'aider en cas de besoin

                      Qt (par exemple) pourra t'offrir tout cela, et sans doute bien plus encore.  Et elle est écrite en C++.

                      tu trouveras beaucoup plus de plaisir à suivre cette évolution "logique" si ton souhait est d'apprendre le C++ ;)

                      Ah, j'allais oublier :

                      • Gardes en mémoire que C et C++ sont des langages totalement différents, et que bon nombre des habitudes que tu as prises en C (et qui sont surement très bonnes, dans le cadre du C) sont ... nocives en C++. 
                      • N'essaye en aucun cas de "porter" tes habitudes issues du C vers le C++
                      • Penses qu'il faut savoir marcher avant de pouvoir courir ;)
                      • 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

                      [C++/CL] utiliser des variables partout!

                      × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                      × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                      • Editeur
                      • Markdown