I'm currently writing a bigger program in C++ and have reached a point were I get problems with the organization. I wonder if namespaces are a way out.
I will try to explain what the program does and show a simplified example of the mess I'm in with it.
Part of the program configures so-called Devices. Each Device needs to be configured differently.
So basically the following is done:
Read in existing Devices. The read devices needs to be analyzed to determine which Device type they are. The
class Devices
does this. It sorts the Devices into the typesDevice_type10_valve
Device_type20_drive
and so on...From another source I get raw data which needs to be analyzed and gets collected into the right device type. I manage all this in
class Devices_config_data_collection
.Why do I not configure them directly in the Devices? Because I need to collect several of these data inputs together since they can have dependencies with each other (e.g. two containers of
Device_config_data_type10_valve
get merged into oneDevice_config_data_type10_valve
).The Data of
Devices_config_data_collection
gets added to theDevices
Devices with the configured data get written out to the source with the configured data.
To achieve this I have the following class hierarchy in pseudo C++ code
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
}
I usually put each class in its own h-file and cpp-file with the name like the class name. The problem I have with this is that the class and file names get very long which doesn't make the code very nice to read.
So I was thinking of adding sub namespaces. One for all Devices to isolate this part from the rest of the program. There are more parts which have nothing to do with devices. And another one for the data classes. Then I could shorten the class names.
Which looks like this in pseudo C++ code:
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
}
Note now I have a class Devices::type10_valve
and Devices::Config_data::type10_valve
.
I wonder if this is a good practice? Also now comes the problem with the cpp and h files. How to handle them now to represent the class names? If I shorten them I have a name clash with Devices::type10_valve
and `Devices::Config_data::type10_valve because they are both type10_valve.cpp/h.
Is it a good practice to put them into subfolders on the hard disk and also refer the folders in the includes?
Please let me know what you think, what are your experiences.
Note I'm using Visual Studio 2017. Any suggestions for organizing issues like this specifically for it are also welcome
If you need more details let me know.