Organizzazione di file / classi di origine in grandi progetti in C ++

1

Attualmente sto scrivendo un programma più grande in C ++ e ho raggiunto un punto in cui ho avuto problemi con l'organizzazione. Mi chiedo se gli spazi dei nomi siano una via d'uscita.

Cercherò di spiegare cosa fa il programma e mostrerò un esempio semplificato del casino in cui mi trovo.

Una parte del programma configura i cosiddetti dispositivi. Ogni dispositivo deve essere configurato in modo diverso.

Quindi in pratica viene fatto quanto segue:

  • Leggi in dispositivi esistenti. I dispositivi di lettura devono essere analizzati per determinare quale tipo di dispositivo sono. Il class Devices fa questo. Ordina i dispositivi nei tipi Device_type10_valve Device_type20_drive e così via ...

  • Da un'altra fonte ottengo dati grezzi che devono essere analizzati e raccolti nel giusto tipo di dispositivo. Gestisco tutto questo in class Devices_config_data_collection .

  • Perché non li configuro direttamente nei dispositivi? Perché ho bisogno di raccogliere più di questi input di dati insieme poiché possono avere dipendenze tra loro (ad esempio due contenitori di Device_config_data_type10_valve vengono uniti in un Device_config_data_type10_valve ).

  • I dati di Devices_config_data_collection vengono aggiunti a Devices

  • I dispositivi con i dati configurati vengono scritti all'origine con i dati configurati.

Per raggiungere questo obiettivo ho la seguente gerarchia di classi nel codice pseudo C ++

namespace Application_name {    // for all the methods in the program

    //Device_config_data_type_base.h   // Device_config_data_type_base.cpp
    class Device_config_data_type_base {
        //..
    };

    //Device_config_data_type10_valve.h   // Device_config_data_type10_valve.cpp
    class Device_config_data_type10_valve : public Device_config_data_type_base {
        //...
    };

    //Device_config_data_type20_drive.h   // Device_config_data_type20_drive_valve.cpp

    class Device_config_data_type20_drive : public Device_config_data_type_base {
        //...
    };

    //.... more derived classes like this from Device_config_data_base


    // Devices_data_collection.h    // Devices_data_collection.cpp
    class Devices_config_data_collection {
    public:
        // put in raw data and make a collection of config data
    private:
        struct data {
            std::vector<Device_config_data_type10_valve> type10;
            std::vector<Device_config_data_type20_drive> type20;
            //... and more
        };

        // more stuff also sorts in valid and invalid inputs
    };


    // Devices_type_base.h // Devices_type_base.cpp
    class Device_type_base {
        //..
    };

    // Device_type10_valve.h // Device_type10_valve.cpp
    class Device_type10_valve : public Device_type_base {
        //..

        void insert_config_data(const Device_config_data_type10_valve& data);
    private:
        // part of the private data is the config data

        Device_config_data_type10_valve config_data;
    };

    // Device_type20_drive.h // Device_type20_drive.cpp
    class Device_type20_drive : public Device_type_base {
        //..
        void insert_config_data(const Device_config_data_type20_drive& data);
    private:
        Device_config_data_type20_drive config_data;
    };

    //.... more derived classes like this

    // Devices.h // Devices.cpp
    class Devices {
    public:
        // Reads in existing Devices from a source

        // providing a function to add the data collection to existing Devices

        // writing out the configured devices back to the source
        void add_data(const Devices_config_data_collection& collection);
    private:
        struct data {
            std::vector<Device_type10_valve> type10;
            std::vector<Device_type20_drive> type20;
            //... and more
        };
    };

    // a lot more parts of the programm with similiar complexity but they are not devices
}

Di solito metto ogni classe nel suo h-file e cpp-file con il nome come il nome della classe. Il problema che ho con questo è che la classe e i nomi dei file diventano molto lunghi e questo non rende il codice molto piacevole da leggere.

Quindi stavo pensando di aggiungere sotto namespace. Uno per tutti i dispositivi per isolare questa parte dal resto del programma. Ci sono più parti che non hanno nulla a che fare con i dispositivi. E un altro per le classi di dati. Quindi potrei abbreviare i nomi delle classi.

Che assomiglia a questo nel codice pseudo C ++:

namespace Application_name {    // for all the methods in the program

    namespace Device {


        namespace Config_data {

            //Device_config_data_type_base.h   // Device_config_data_type_base.cpp
            class Type_base {
                //..
            };

            //Device_config_data_type10_valve.h   // Device_config_data_type10_valve.cpp
            class Type10_valve : public Type_base {
                //...
            };

            //Device_config_data_type20_drive.h   // Device_config_data_type20_drive_valve.cpp

            class Type20_drive : public Type_base {
                //...
            };

            //.... more derived classes like this from Device_config_data_base

        }

        // Devices_data_collection.h    // Devices_data_collection.cpp
        class Collection {
        public:
            // put in raw data and make a collection of config data
        private:
            struct data {
                std::vector<Config_data::Type10_valve> type10;
                std::vector<Config_data::Type20_drive> type20;
                //... and more
            };

            // more stuff also sorts in valid and invalid inputs
        };

        // Devices_type_base.h // Devices_type_base.cpp
        class Type_base {
            //..
        };

        // Device_type10_valve.h // Device_type10_valve.cpp
        class Type10_valve : public Type_base {
            //..

            void insert_config_data(const Config_data::Type10_valve& data);
        private:
            // part of the private data is the config data

            Config_data::Type10_valve config_data;
        };

        // Device_type20_drive.h // Device_type20_drive.cpp
        class Type20_drive : public Type_base {
            //..
            void insert_config_data(const Config_data::Type20_drive& data);
        private:
            Config_data::Type20_drive config_data;
        };

        //.... more derived classes like this


    }

    // Devices.h // Devices.cpp
    class Devices {
    public:
        // Reads in existing Devices from a source
        // providing a function to add the data collection to existing Devices
        // writing out the configured devices back to the source
        void add_data(const Devices_config_data_collection& collection);
    private:
        struct data {
            std::vector<Device_type10_valve> type10;
            std::vector<Device_type20_drive> type20;
            //... and more
        };
    };

    // a lot more parts of the program with similar complexity but they are not devices
}

Nota ora ho una classe Devices::type10_valve e Devices::Config_data::type10_valve .

Mi chiedo se questa è una buona pratica? Inoltre ora arriva il problema con i file cpp e h. Come gestirli ora per rappresentare i nomi delle classi? Se li accorro, ho un conflitto di nomi con Devices::type10_valve e 'Devices :: Config_data :: type10_valve perché sono entrambi type10_valve.cpp / h.

È una buona pratica metterli in sottocartelle sul disco rigido e anche fare riferimento alle cartelle negli include?

Per favore fatemi sapere cosa ne pensate, quali sono le vostre esperienze.

Nota Sto usando Visual Studio 2017. Qualsiasi suggerimento per l'organizzazione di problemi come questo in particolare per questo è anche benvenuto

Se hai bisogno di maggiori dettagli fammi sapere.

    
posta Sandro4912 27.07.2018 - 18:57
fonte

1 risposta

5

I namespace sono un ottimo modo per organizzare il tuo codice (basi di codice più grandi).

E come hai detto, avere la struttura dei filesystem simula in qualche modo i namespace, è anche una buona pratica.

La chiave per fare questo bene sta nel trovare la giusta decomposizione organizzativa, che ovviamente è intimamente legata alla tua particolare applicazione.

Ma quello che mi hai offerto come esempio mi è sembrato giusto.

Un esempio di una libreria di grandi dimensioni che utilizza questo tipo di schema organizzativo è Stroika (classe stream condivisa)

Un altro piccolo suggerimento, non userei un nome come "global_namespace". Ci andrei - usa il nome della tua applicazione, o progetto a cui è dedicato tutto il codice sorgente (nota: C ++ ha qualcosa chiamato spazio globale e significa qualcosa di diverso dal tuo).

    
risposta data 27.07.2018 - 19:43
fonte

Leggi altre domande sui tag