Standardkonform oder nicht?



  • Hi,

    folgender Code hat mit MSVC 6.0 einwandfrei compiliert, aber mit Studio .net 2003 will er nicht mehr. 😞

    Ist er nicht standardkonform oder was ist sonst falsch?

    // FileSystemDataDirectory.hpp
    #include <vector>
    #include "Global.hpp"
    #include "Engine\DataDirectory.hpp"
    
    namespace AGE
    {
    
    class FileSystemDataDirectory : public DataDirectory
    {
    public:
        FileSystemDataDirectory(const String &strPath);
        virtual ~FileSystemDataDirectory(void);
    
        virtual void Refresh(void);
    
        virtual unsigned int GetItemCount(void) const;
        virtual String GetItemName(unsigned int nCount) const;
        virtual Pointer<DataStream> CreateStream(const String &strName,
            StreamFlags StreamFlags) const;
    
    private:
        std::vector<String> m_Files;
    };
    
    class FileSystemDataDirectory::Factory
    {
    public:
        virtual ~Factory(void);
    
        virtual bool CanCreateDataDirectory(const String &strPath) const;
        virtual Pointer<DataDirectory> CreateDataDirectory(const String &strPath) const;
    };
    
    } // Namespace
    
    // DataDirectory.hpp
    namespace AGE
    {
    
    class DataDirectory
    {
    public:
        class Factory;
        class StreamEnumerator;
    
        AGEAPI DataDirectory(const String &strPath);
        virtual ~DataDirectory(void) {}
    
        AGEAPI virtual void Refresh(void) = 0;
    
        AGEAPI Pointer<StreamEnumerator> CreateStreamEnumerator(void) const;
        AGEAPI String GetDirectoryPath(void) const;
    
        virtual unsigned int GetItemCount(void) const = 0;
        virtual String GetItemName(unsigned int nCount) const = 0;
        virtual Pointer<DataStream> CreateStream(const String &strName,
            StreamFlags StreamFlags) const = 0;
    
    protected:
        String m_strPath;
    };
    
    class DataDirectory::Factory
    {
    public:
        virtual ~Factory(void);
    
        virtual bool CanCreateDataDirectory(const String &strPath) const = 0;
        virtual Pointer<DataDirectory> CreateDataDirectory(const String &strPath) const = 0;
    };
    
    class DataDirectory::StreamEnumerator
    {
    public:
        AGEAPI StreamEnumerator(const DataDirectory &DataDirectory);
    
        AGEAPI StreamEnumerator operator++(void);
    
        AGEAPI String GetStreamName(void) const;
        AGEAPI String Cycle(void);
    
    private:
        const DataDirectory &m_DataDirectory;
        unsigned int m_nCurStream;
    };
    
    }  // Namespace
    

    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\AGEFileSystemStorage\FileSystemDataDirectory.hpp(40) : error C2535: 'AGE::DataDirectory::Factory::~Factory(void)': Memberfunktion bereits definiert oder deklariert
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(47): Siehe Deklaration von 'AGE::DataDirectory::Factory::~Factory'
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\AGEFileSystemStorage\FileSystemDataDirectory.hpp(42) : error C2535: 'bool AGE::DataDirectory::Factory::CanCreateDataDirectory(const AGE::String &) const': Memberfunktion bereits definiert oder deklariert
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(49): Siehe Deklaration von 'AGE::DataDirectory::Factory::CanCreateDataDirectory'
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\AGEFileSystemStorage\FileSystemDataDirectory.hpp(43) : error C2535: 'AGE::Pointer<type> AGE::DataDirectory::Factory::CreateDataDirectory(const AGE::String &) const': Memberfunktion bereits definiert oder deklariert
    with
    [
    type=AGE::DataDirectory
    ]
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(50): Siehe Deklaration von 'AGE::DataDirectory::Factory::CreateDataDirectory'
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\AGEFileSystemStorage\FileSystemDataDirectory.hpp(44) : error C2535: 'void AGE::DataDirectory::Factory::__local_vftable_ctor_closure(void)': Memberfunktion bereits definiert oder deklariert
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(51): Compiler hat hier 'AGE::DataDirectory::Factory::__local_vftable_ctor_closure' erzeugt
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\AGEFileSystemStorage\FileSystemDataDirectory.hpp(44) : error C2535: 'void *AGE::DataDirectory::Factory::__delDtor(unsigned int)': Memberfunktion bereits definiert oder deklariert
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(51): Compiler hat hier 'AGE::DataDirectory::Factory::Factory' erzeugt
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\AGEFileSystemStorage\FileSystemDataDirectory.hpp(44) : error C2535: 'void *AGE::DataDirectory::Factory::__vecDelDtor(unsigned int)': Memberfunktion bereits definiert oder deklariert
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(51): Compiler hat hier 'AGE::DataDirectory::Factory::Factory' erzeugt
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\AGEFileSystemStorage\Plugin.cpp(25) : error C2259: 'AGE::DataDirectory::Factory': Instanz von abstrakter Klasse kann nicht erstellt werden
    aufgrund folgender Member:
    'bool AGE::DataDirectory::Factory::CanCreateDataDirectory(const AGE::String &) const': Rein virtuelle Funktion wurde nicht definiert
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(49): Siehe Deklaration von 'AGE::DataDirectory::Factory::CanCreateDataDirectory'
    'AGE::Pointer<type> AGE::DataDirectory::Factory::CreateDataDirectory(const AGE::String &) const': Rein virtuelle Funktion wurde nicht definiert
    with
    [
    type=AGE::DataDirectory
    ]
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Include\Engine\DataDirectory.hpp(50): Siehe Deklaration von 'AGE::DataDirectory::Factory::CreateDataDirectory'

    Und dann noch was Komisches, ist aber nur eine Warnung:

    extern "C"
    {
        AGEPLUGIN unsigned int AGEVersion(void);
        AGEPLUGIN void AGELoad(AGE::Kernel *pKernel);
        AGEPLUGIN void AGEUnload(AGE::Kernel *pKernel);
    }
    
    void AGELoad(AGE::Kernel *pKernel)
    {
        GUARD([AGEFileSystemStorage]AGELoad);
    
        (pKernel->GetDataStorageMgr()).RegisterDataDirectoryFactory("filesystem",
            new AGE::FileSystemDataDirectory::Factory);
    
        UNGUARD;  // Hier kann eine Exception fliegen
    }
    

    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\AGEFileSystemStorage\Plugin.cpp(27) : warning C4297: 'AGELoad': Die Funktion löst eine unerwartete Ausnahme aus
    '__declspec(nothrow)' oder 'throw()' wurde für die Funktion angegeben
    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\AGEFileSystemStorage\Plugin.cpp(27) : warning C4297: 'AGELoad': Die Funktion löst eine unerwartete Ausnahme aus
    '__declspec(nothrow)' oder 'throw()' wurde für die Funktion angegeben

    Liegt das am __declspec(dllexport)? Früher hatte ich damit nie Warnungen!

    ChrisM



  • Hallo,
    also in meinen Augen macht der Code keinen sinn.

    class FileSystemDataDirectory::Factory

    FileSystemDataDirectory hat keine innere Klasse namens Factory deklariert. Also kannst du auch keine definieren.

    Schaut man nun hat aber in die Basisklasse (DataDirectory) sieht man, dass diese eine solche innere Klasse deklariert. Da in der entsprechenden h-Datei diese innere Klasse aber bereits eine Definition hat, kannst du sie in der abgeleiteten Klasse nicht nochmal definieren.

    Der Code ist also nicht konform.

    [ Dieser Beitrag wurde am 11.07.2003 um 19:28 Uhr von HumeSikkins editiert. ]



  • Ich hab es jetzt behoben und die Subklasse in der abgeleiteten Klasse umbenannt, nur noch eine Frage dazu: Warum hat VC 6.0 das anstandslos compiliert?

    Und zu der Warnung: OK, das ist jetzt kein Standard-C++ mehr, aber weiß jemand, wie ich die ohne #pragma wegkriege, also quasi "löse" 🙄

    Und dann noch was, sorry, falls ich euch hier nerve:

    void AGELoad(AGE::Kernel *pKernel)  // Steht ja schon oben
    {
        GUARD([AGEFileSystemStorage]AGELoad);
    
        (pKernel->GetDataStorageMgr()).RegisterDataDirectoryFactory("filesystem",
            new AGE::FileSystemDataDirectory::FileSystemFactory);
    
        UNGUARD;
    }
    

    Hier kriege ich neben den zwei Warnung auch einen Fehler in dem RegisterDataDirectoryFactory-Aufruf:

    c:\Dokumente und Einstellungen\Chris\Eigene Dateien\Programmieren\Projekte\AGE\Source\AGEFileSystemStorage\Plugin.cpp(25) : error C2664: 'AGE::DataStorageMgr::RegisterDataDirectoryFactory': Konvertierung des Parameters 2 von 'AGE::FileSystemDataDirectory::FileSystemFactory *' in 'AGE::Pointer<type>' nicht möglich
    with
    [
    type=AGE::DataDirectory::Factory
    ]
    Quelltyp konnte von keinem Konstruktor angenommen werden, oder die Überladungsauflösung des Konstruktors ist mehrdeutig

    Wie man sieht, erwartet RegisterDataDirectoryFactory() als zweiten Parameter ein AGE::DataDirectory::Factory-Zeiger (Smart Pointer-Templateinstanz um genauzusein), ich versuche aber, ein AGE::FileSystemDataDirectory::FileSystemFactory zu übergeben, dass ja eigentlich die Factory implementieren soll. Ist ja klar, dass das nicht geht, aber wie kriege ich es hin, dass es geht?

    ChrisM



  • VC++ 2003 ist Standardkonformer als das alte 6.0. Ist übrigens eine neue Anstrengung von MS wieder C++ mehr zu unterstützen und den Compiler entsprechend anzupassen.



  • D.h. mein ganzer alter Code war nicht standardkonform.

    Nur jetzt nochmal, ich vereinfach jetzt mal, wie geht das:

    class Base
    {
    public:
    class BaseSub;
    };
    
    class Base::BaseSub
    {
    public:
    virtual void muh() = 0;
    };
    
    case Derived : public Base
    {
    public:
    // Wie implementier ich jetzt die Subklasse? Eigentlich müsst ich ja hier gar nichts mehr schreiben
    };
    
    // Und dann einfach so...
    class Derived::BaseSub
    {
    virtual void muh();
    };
    
    // Aber das geht ja nicht (im neuen Studio .net 2003)
    
    // Und dann irgendwo neue Instanz erstellen: new Derived::BaseSub geht auch nicht :(
    

    Deswegen hab ich ja jetzt das Ganze so gemacht:

    class Derived : public Base
    {
    public:
    class DerivedSub;
    };
    
    class Derived::DerivedSub
    {
    virtual void muh();
    };
    

    Aber dann kann ich ja logischerweise keine Derived::DerivedSub-Instanz als Base::BaseSub-Zeiger übergeben!

    ChrisM



  • dann lass DerivedSub von BaseSub erben.
    was du willst, geht anders nicht. Derived hat nicht automatisch eine eigene BaseSub Klasse. die hat nur Base. bzw. ist sie über Derived::Sub auch ansprechbar, aber nicht "überladbar".

    probier mal den code aus, zum herumtesten:

    #include <iostream>
    using namespace std;
    
    class Base {
    public:
        class Sub;
    };
    
    class Base::Sub {
    public:
        virtual void x () const { cout << "Base::Sub::x\n"; }
    };
    
    class Derived : public Base {
    public:
        class Sub;
    };
    
    class Derived::Sub : public Base::Sub {
    public:
        virtual void x () const { cout << "Derived::Sub::x\n"; }
    };
    
    int main () {
        Derived::Base::Sub().x();
        Derived::Sub().x();
        Base::Sub().x();
    }
    

    und dann lass das ": public Base::Sub" weg.
    merkst du? mit dem neuen Derived::Sub überdeckst du einfach den Namen. Ein überladen von ganzen Klassen geht nicht.



  • Irgendwie erscheint mir dein Beispiel logisch, aber warum hat Visual C++ 6.0 so einen Müll anstandslos compiliert und (richtig) ausgeführt, d.h. ich konnte wirklich Derived::Sub-Zeiger als Base::Sub-Zeiger übergeben und die reinvirtuellen Methoden von dem Base::Sub-Zeiger aufrufen (dann wurden natürlich die von dem Derived::Sub-Objekt, auf das der Zeiger in Wirklichkeit zeigte, ausgeführt)?

    ChrisM


Anmelden zum Antworten