Search code examples
c++constructordefault-constructor

How to handle objects that dont have a default constructor but are constructed in another constructor?


I have the following sample code

class ClassB {
    public:
    ClassB(int i); // No default constructor
}

class ClassA {
    ClassB obj; //NOT a pointer
    public 
    ClassA() {
        //calculate someInt;
        obj = ClassB(someInt); // doesnt work
    }

}

How do I initialize obj? The compiler complains about no appropriate default constructor available for obj


Solution

  • The best design solution for you would be to initialize member obj in the initialization list like this:

    ClassA() : obj(someInt) { }
    

    However, another option for you would be to declare the default constructor for ClassB like this:

    ClassB() {}
    

    or simply let the compiler create the one for you by using this:

    ClassB() = default;
    

    From C++ Standard this is:

    defaulted default constructor: the compiler will define the implicit default constructor even if other constructors are present.

    If you go for a second option, then the following code would pass without the error:

    #include <iostream>
    
    class ClassB {
    public:
        ClassB() = default;
        ClassB(int i);
    };
    
    class ClassA {
        ClassB obj;
    public: 
        ClassA() {
            int someInt = 0;
            obj = ClassB(someInt);
        }
    };
    
    int main() {
    
        return 0;
    }
    

    Check it out live

    Conclusion

    I would deeply recommend using the first option, the one with the initialization list because it is not needed to default construct objects before and then assigning to them. Also, this is the only option for objects that don't have an assignment operator.

    UPDATE 1

    One more way around this problem is using the std::shared_ptr<ClassB> obj in your ClassA as follows:

    #include <iostream>
    #include <memory>
    
    class ClassB {
    public:
        ClassB(int i);
    };
    
    class ClassA {
        std::shared_ptr<ClassB> obj;
    public: 
        ClassA() {
            int someInt = 0;
            obj = std::make_shared<ClassB>(someInt);
        }
    };
    
    int main() {
    
        return 0;
    }
    

    UPDATE 2

    One more possibility that came up to my mind is to calculate integer in a separate function and the just call it as part of the initialization list like in the following code:

    #include <iostream>
    
    class ClassB {
    public:
        ClassB(int i);
    };
    
    class ClassA {
        ClassB obj;
    public: 
        ClassA()
            : obj(calculate())
        {}
    
    private:
        int calculate() {
            return 1;
        }
    };
    
    int main() {
        return 0;
    }
    

    Check it out live