views:

659

answers:

12

Can I have a constructor work in different ways if the argument is of different type? i.e. int or float.

Let's say that if I do, new Object(3) the constructor fills an array with 3 at every index

Let's say that if I do, new Object(3.5) the constructor fills an array with index+3.5 for every index

Let's say that if I do, new Object() the constructor fills an array with 0.0 at every index

Is there a way to achieve this with just one constructor? Or do I need three different constructors?

Thanks.

A: 

You need 3 different constructors.

Andrew Coleson
A: 

Multiple constructors would be required, one for each different argument type.

Alex B
A: 

You will either need three different constructors (overloading them) or one with some attributes with default values.

This can be achieved, however I would suggest using 3 different constructors for code clarity, etc.

Rekreativc
+1  A: 

If you only care about built in types you can take advantage of type promotions and default values:

struct Object
{
    Object(double value = 0.0)
    {
     // do that thing you do
    }
};
Andrew Khosravian
Right, but how do you accomplish 3 different actions based on what was passed in? They'll all be upconverted to double, so you won't know which one to do.
Andrew Coleson
You could always set your default value to something you would _know_ it's default and then check which of the three values (three - example) has been passed to the constructor. As I stated in my reply, you can do this, however it would be ugly and unclear.
Rekreativc
You're assuming they'd have different values -- what if he wants something different for <no value>, 3, and 3.0 simply because of its type?
Andrew Coleson
He could use explicit to prevent" conversion between types, then it would be obvious which attribute received a value (in case only one would receive a value at the time). Not that this really matters, since we all agree that it would be bad practice to do this and a nightmare to tweak later!
Rekreativc
Right, I'm not trying to be picky, I was just curious if there actually was a way to determine between different types with the same constructor. :)
Andrew Coleson
+3  A: 

You can do it with one constructor, but it will be ugly as hell. A 3 constructors approach is proffered because it separates the usage and simplify the code.

Ido
+5  A: 

Of course you can have many constructors! Overloading for constructors work the same as for any function/member.

Just remember that sometimes compiler can implicitly call a constructor that you wouldn't like to have been called - by automatic conversion of arguments.

You can add keyword explicit to the constructor declaration to forbid any automatic conversion.

Marcin Gil
A: 

No only you need three different constructors, you want three different constructors. It'll keep the code cleaner and easier to understand, maintain and unit test.

Franci Penov
+1  A: 

As long as the parameter passed is always of the same type you can get away with using one constructor, otherwise you need several.

It seems as though the most obvious solution to this would be to insert a switch statement inside your object constructor.

Example:

public Object(int num) { switch (num) { case 1: array[i] = num; break case 2: array[i] = num * 2; }

}

Corey Sunwold
He wants different actions based on the type of the argument, not its value.
Andrew Coleson
A: 

You can factor the behavior Object() and Object(3) because they do the same thing. Just write your constructor like this:

class Object {
    // fills an array with n at every index
    Object(int n = 0) { ... }
};

The problem is that the constructor with a float (3.5 in the example) has to be separated, like this:

class Object {
    // fills an array with n at every index
    Object(int n = 0) { ... } // handles Object() AND Object(3)

    // fills an array with index + n at every index
    Object(float n)   { ... } // handles Object(3.5)
};
random
+1  A: 

It is usually a bad idea to have such different behaviour for a constructor purely based on the type of the parameter, especially for built-in types that are easily implicitly convertible between each other.

Having said that, purely as a programming exercise, it is possible to do this using one constructor, but you would have to use a proxy class with implicit conversion from the types to be distinguished between to achieve what you want. As a pre-canned solution, boost::variant would fit the requirement. You may not consider this to meet the requirements of a single constructor, as it relies on multiple constructors (or a constructor template) of a second class.

class Object
{
public:
        Object( const boost::variant< int, double >& val = 0 )
        {
                switch( val.which() )
                {
                case 0:
                        // TODO: Fill array with val
                        break;
                case 1:
                        // TODO: fill array with val + index
                        break;
                }
        }

// TODO: Add array member
};
Charles Bailey
A: 

Use 3 different constructors as the logic is different depending upon the type of the parameter. Also, be aware of the type promotions done by the compiler..otherwise you might end up with surprises when the code is executed.

Naveen
+1  A: 

It sounds like you're up for a maintenance nightmare. I suggest yo use the named constructor idiom instead:

class Object
{
public:
    // Sets all elements to 0.
    Object();

    // Sets all elements to value.
    static Object Fill(double value);

    // Sets all elements to the previous + delta, beginning at start.
    static Object Accumulate(double start, double delta);
};
Johann Gerell