c++constructorbuilt-in-types

Is ok to have one constructor for each built in data types C++


Let's say we are going to create a class whose constructor or constructors will save in the variable words a very long number:

class myClass {
    private:
        unsigned long long int words;

    public:
        ...
}

But I want to be able to initialize the class using any built-in type, for example:

int a; myClass A(a);
float b; myClass B(b);
long long int c; myClass C(c);

Should I implemeting a constructor for each one of the types (listed here) in the form:

...
public:
    ...
    myClass(const short int i): 
        words(i) {}

    myClass(const unsigned short int i);
        words(i) {}

    etc...

Or should I just implement the constructor for unsigned long long int:

...
public:
    ...
    myClass(const unsigned long long int i): 
        words(i) {}

    ...

What I understand is that using the first option (one for each), this will happen:

int a; myClass(a);
// Call constructor myClass(const int i)
// Convert the value i to unsigned long long int and initialize words with it

With the second option (one for all):

int a; myClass(a);
// Convert i to unsigned long long int and this new value as a parameter for the constructor
// Initialize words with it

Now, which one should I use ?. I'm guessing it's just better to use one constructor for unsigned long long int.

Is there any scenario where this having a constructor for each one is better?


Solution

  • The only reason you should make more than one constructor is if extra handling or conversion logic is required. For example:

    #include <string>
    #include <iostream>
    
    class myClass
    {
    
    public:
        unsigned long long int words;// public for ease of example
    
        // will consume anything convertable to unsigned long long
        myClass(unsigned long long int val) :
                words(val)
        {
        }
    
        // will consume anything convertable to std::string, and then convert 
        // the string to unsigned long long
        myClass(std::string val) :
                words(std::stoull(val))
        {
        }
    
    };
    
    int main()
    {
        std::cout << myClass{ 10 }.words << ": 10" << std::endl;
        std::cout << myClass{ -10 }.words << ": -10 (Two's compliment wrap)" << std::endl;
        std::cout << myClass{ 3.14 }.words << ": 3.14 (Truncated)" << std::endl;
        std::cout << myClass{ "10" }.words << ": \"10\"" << std::endl;
        std::cout << myClass{ "-10" }.words << ": \"-10\" (Two's compliment wrap)" << std::endl;
    }
    

    10 is converted easily. -10 and 3.14 are converted, but will generate warnings because the value will be damaged by the translation. "10" and "-10" will be accepted by the string-parametered constructor, but "-10" will be mangled by std::stoull. Additional logic, and probably use of strtoull, will be required to handle this, if required.