There is a simple program on with ++. There are three classes, one contains private fields 2 others. When the constructor is called first, the constructors of the others are implicitly called. The question is why? and more importantly, how to avoid it?

class Device { private: Date date; TypeSensor type; int placeBinding; Sensor sensor; ...... } 

That is, when you call a constructor device, the Date constructor is called. All anything, but TypeSensor needs to be initialized earlier than the other fields. Therefore, I wonder if there are ways to solve this problem.

 enum TypeSensor { ACCELEROMETER, PROXYMETER, TEMPERATURE }; class Sensor { string unitOfMeasured; int maximum; int minimum; float value; ..... } 

    3 answers 3

    The order of initialization of variables is determined by their following in the class declaration. Rearrange the TypeSensor and Date class TypeSensor so that the TypeSensor initialized first.

     class Device { private: TypeSensor type; Date date; int placeBinding; Sensor sensor; } 

    It is not clear what you want to avoid. When creating an object, all fields of the class must be initialized. If the class declaration is Date date; then this field must be initialized when creating the Device .

    However, if you want to avoid calling the Date constructor, you can make a pointer to it Date* date; and allocate memory elsewhere.

    • The fact is that this enumeration (I wanted to initialize it in the Device constructor, that is, that the user himself entered the dial and then the enum value was already determined), and as far as I know, there is no constructor there ... - Andriy
    • Show implementation of the constructor Device - Rikitikitavi
    • Device::Device() { int n; cout << "choise 1, 2 or 3 type of sensor: " << endl; cout << "1. ACCELEROMETER" << endl; cout << "2. PROXYMETER" << endl; cout << "3. TEMPERATURE" << endl; cin >> n; switch (n) { case 1: this->type = TypeSensor::ACCELEROMETER; break; case 2: this->type = TypeSensor::PROXYMETER; break; case 3: this->type = TypeSensor::TEMPERATURE; break; default: break; } Sensor s; this->sensor = s; } Device::Device() { int n; cout << "choise 1, 2 or 3 type of sensor: " << endl; cout << "1. ACCELEROMETER" << endl; cout << "2. PROXYMETER" << endl; cout << "3. TEMPERATURE" << endl; cin >> n; switch (n) { case 1: this->type = TypeSensor::ACCELEROMETER; break; case 2: this->type = TypeSensor::PROXYMETER; break; case 3: this->type = TypeSensor::TEMPERATURE; break; default: break; } Sensor s; this->sensor = s; } - Andriy
    • The initialization of objects completely suits me, the fact is that there is no constructor in enum (TypeSensor), so I can’t correctly initialize it. - Andriy
    • This is not necessary. Make a separate input function, and add the SensorType - vegorov parameter to the constructor

    In C ++, the constructor of a class object always invokes the constructors of all its sub-objects. This is how the C ++ language works. You can not avoid it.

    The order of initialization of the sub-objects is determined by the type of the sub-object (the basic sub-object or the sub-object member) and the order of the sub-object declaration among similar sub-objects. In your case, the order of initialization you require can be achieved simply by reordering class member declarations.

    However, if you need some specific order of initialization of subobjects, then it is better to achieve it not by manipulating the declaration order, but by other means. Namely: it is better to postpone the initialization of all or some sub-objects, and then execute it manually in the order you need. This can be achieved in different ways.

    • You can make the default sub-object constructor do nothing, and provide a special method for actual initialization.

    • You can do the aggregation of sub-objects not directly, but through a smart pointer std::unique_ptr .

    • Instead of aggregating objects directly, you can aggregate std::optional .

    Etc.

      Not related to the issue, but you have a SensorType from the class Sensor . Maybe it makes sense to make the SensorType part of the Sensor class and pass it to the constructor? Somehow, for example:

       class Sensor { public: enum class Type{ DEFAULT = 0, ACCELEROMETER = 0, PROXYMETER = 1, TEMPERATURE = 2 }; explicit Sensor(const Type& type = Type::DEFAULT): m_unitOfMeasured{}, m_maximum{1}, m_minimum{0}, m_value{0.0}, m_type{type} { switch (m_type) { case Type::ACCELEROMETER: m_unitOfMeasured = "acceleration"; ... break; case Type::PROXYMETER: m_unitOfMeasured = "level"; ... break; case Type::TEMPERATURE: m_unitOfMeasured = "degree"; ... break; default: ... break; } } private: std::string m_unitOfMeasured; int m_maximum; int m_minimum; float m_value; Type m_type; }; class Date{}; class Device { public: Device(const Sensor::Type& sensorType = Sensor::Type::DEFAULT): m_sensor{sensorType}, m_date{}, m_placeBinding{} {} private: Sensor m_sensor; Date m_date; int m_placeBinding; }; 

      UPD. Well then, something like this:

       enum class SensorType{ DEFAULT = 0, UNKNOW = 0, ACCELEROMETER = 1, PROXYMETER = 2, TEMPERATURE = 3 }; class Sensor { public: Sensor(const SensorType& type = SensorType::DEFAULT): m_unitOfMeasured{}, m_maximum{1}, m_minimum{0}, m_value{0.0}, m_type{type} { switch (m_type) { case SensorType::ACCELEROMETER: m_unitOfMeasured = "acceleration"; break; case SensorType::PROXYMETER: m_unitOfMeasured = "level"; break; case SensorType::TEMPERATURE: m_unitOfMeasured = "degree"; break; default: break; } } private: std::string m_unitOfMeasured; int m_maximum; int m_minimum; float m_value; SensorType m_type; }; class Date{}; class Device { public: Device(const Date& date, const int placeBinding, const SensorType& sensorType= SensorType::DEFAULT): m_type{sensorType}, m_sensor{sensorType}, m_date{date}, m_placeBinding{placeBinding} {} Device(const Device& other): m_type{other.m_type}, m_sensor{other.m_sensor}, m_date{other.m_date}, m_placeBinding{other.m_placeBinding} { } static Device createByUser(){ int n; std::cout << "choise 1, 2 or 3 type of sensor: " << std::endl; std::cout << "1. ACCELEROMETER" << std::endl; std::cout << "2. PROXYMETER" << std::endl; std::cout << "3. TEMPERATURE" << std::endl; std::cin >> n; if (n >= 1 && n <= 3){ return Device(Date(), 0, static_cast<SensorType>(n)); }else{ return Device(Date(), 0); } } private: SensorType m_type; Sensor m_sensor; Date m_date; int m_placeBinding; }; 
      • I agree, the architecture is bad, but these are the laboratory conditions, the sensor type must be a field in the device, and not in the sensor itself. - Andriy