2016-03-19 13 views
0

Ich habe ein persönliches Projekt mit C++ Builder 2006 bei der Arbeit entwickelt. Jetzt möchte ich es zu Hause entwickeln, mit freien Stoffen. Also habe ich Visual Studio 2015 installiert (als zweite Wahl, da ich Codeflite + wxWidgets nicht funktionierte) und habe ein neues Projekt für die Lösung/CLR gestartet.Erste Schritte mit VS2015, mit C++. Verwalteter/nicht verwalteter Klassenfehler. Was mache ich falsch?

Aber ich hämmere meinen Kopf gegen einen Fehler. Das ist was ich habe;

cSQSequencer-Klasse, erstellt mit dem Add-> Class Wizard.

cSQSequencer.h

#pragma once 
#include <string> 

class cSQSequencer 
{ 
public: 
    cSQSequencer(); 
    ~cSQSequencer(); 
    std::string   Name; 
    void Reset() { 
     Name=""; 
    }; 
}; 

cSQSequencer.cpp

#include "cSQSequencer.h" 

cSQSequencer::cSQSequencer() 
{ 
} 

cSQSequencer::~cSQSequencer() 
{ 
} 

Dann i eine Form haben, suchte ich einen Weg, um meine Klasse fügen Sie einige Assistenten wie Funktionen zum Hinzufügen, aber ich habe alles gefunden, also habe ich manuell die Zeilen hinzugefügt, die zu meiner Klasse gehören:

SysExExpMainForm

#pragma once 
#include "cSQSequencer.h" 

namespace EnsoniqSQKSSysExexporter { 

    using namespace System; 
    using namespace System::ComponentModel; 
    using namespace System::Collections; 
    using namespace System::Windows::Forms; 
    using namespace System::Data; 
    using namespace System::Drawing; 

    /// <summary> 
    /// Riepilogo per SysExExpMainForm 
    /// </summary> 

    public ref class SysExExpMainForm : public System::Windows::Forms::Form 
    { 
    public: 
     cSQSequencer SQSeq; 
     SysExExpMainForm(void) 
     { 
      InitializeComponent(); 
      // 
      //TODO: aggiungere qui il codice del costruttore. 
      // 
      SQSeq.Reset(); 
     } 

    protected: 
    [ all the other code that follows.... ] 

Der Fehler ist in der Zeile "cSQSequencer SQSeq;". Es heißt (mehr oder weniger, übersetzt aus dem Italienischen) "Ein Mitglied einer verwalteten Klasse kann kein nicht-verwalteter Typ sein".

Was soll ich tun? Ist das die richtige Methode zum Hinzufügen einer Klassenvariablen in einem Formular? Oder sollte ich eine andere Art von Projekt zu starten (aber dies ist die einzige, die ich gefunden, wo ich ein Formular hinzufügen können ....)

+1

Der "Formulardesigner" ist nur für .NET-Code, der sie speichert eine separate Version für C++ zu speichern. Es gibt einen GUI-Designer (genannt "Dialog" -Editor, nicht "Forms") für natives C++, aber nicht alle Editionen haben es. C++/CLI-Formularcode kann normale C++ - Klassen verwenden, jedoch nur als Zeiger. Zum Beispiel mit [mein Smart Pointer] (http://codereview.stackexchange.com/q/1695/2150) können Sie 'clr_scoped_ptr SQSeq;' schreiben, erstellen Sie eine Instanz Ihrer Klasse im Formularkonstruktor und dann benutze es normal. –

Antwort

1
cSQSequencer SQSeq; 

Die Fehlermeldung Sie bekam ist für diese Erklärung genau, mit nativen C++ - Objekte als Mitglieder eines Garbage Collection-Objekts wie Form sind sehr, sehr gefährlich. Gefährlich genug, dass die Spracherweiterung es komplett verbietet.

Die vielleicht nicht naheliegende Sache, die mit Garbage Collection-Objekten passiert, ist, dass sie im Speicher verschoben werden können. Dies passiert, wenn der Collector den Heap nach einem Sammlungsdurchgang komprimiert. Die Komprimierung macht den Heap sehr effizient, verbessert die Fundstelle und verhindert die Fragmentierung.

Alle Zeiger auf ein solches verschobenes Objekt werden vom Kollektor aktualisiert, um sie erneut auf das verschobene Objekt zu verweisen. Aber das kann nur für Zeiger funktionieren, von denen der Sammler weiß. Verwaltete Zeiger. Nicht-Zeiger, die von nativen C++ - Objekten verwendet werden, zeigen immer noch auf, wo solch ein natives Objekt lebte. Jetzt auf Müll zeigen. Das ist in der aktuellen cSQSequencer Klasse nicht so groß, dass wir es trotzdem sehen können, aber das könnte nicht so bleiben. Beachten Sie, dass das Member std :: string bereits ein Problem ist, eine Template-Klasse, die intern einen Zeiger auf den zugrunde liegenden String-Puffer enthält.

Zu gefährlich, der Compiler verbietet es direkt. Was Sie stattdessen verwenden müssen, ist ein Zeiger oder eine Referenz auf das native Objekt. Es bezieht sich jetzt auf Speicher, der nicht aus dem GC-Heap zugeordnet ist und daher stabil ist.So werden Sie brauchen:

cSQSequencer* SQSeq; 

und der Tanz tun zu schaffen und zu zerstören:

MyForm(void) : SQSeq(new cSQSequencer) { 
     // etc... 
    } 

    ~MyForm() { 
     delete SQSeq; 
     SQSeq = nullptr; 
     // etc.. 
    } 

    !MyForm() { 
     delete SQSeq; 
    } 

Notiere die Finalizerthread für die Klasse, !MyForm(), stellen Sie sicher, dass Bereinigung geschieht unabhängig davon, ob die Client-Code disponiert das Objekt ordnungsgemäß. Oder, um es anders auszudrücken: Wenn es vergisst, den Operator delete zu verwenden, stellt der Finalizer sicher, dass es trotzdem passiert. In nativem C++ gibt es dafür keine Entsprechung. Technisch können Sie es in diesem speziellen Fall weglassen, Form-Objekte haben eine ziemlich gute Garantie, entsorgt zu werden, die Winforms-Laufzeit sorgt dafür. Aber machen Sie es sich zur Angewohnheit, es trotzdem aufzunehmen, Sie werden nicht eines Tages enttäuscht sein müssen.

Dieser Code schreit wahrscheinlich "Smart Pointer" für Sie. Beispiele sind Nish's CAutoNativePtr und Kenny Kerr's AutoPtr.

Lesen Sie auch this post, um zu erfahren, wie Sie eine Konsolen-App-Projektvorlage zur Unterstützung einer Benutzeroberfläche ordnungsgemäß konvertieren können. Es gibt viele da draußen, die das falsch bekommen, auch der Grund, warum Sie die SQSeq = nullptr-Zuweisung im Destruktor nicht weglassen sollten. Im Gegensatz zu nativem C++ kann der Destruktor mehr als einmal ausgeführt werden. Nur der Finalizer wird garantiert einmal ausgeführt.