May I please have some help!

Apr 15, 2013 at 3:02am
In this Text:

"If you define a constructor with a single parameter, the compiler will use this constructor for implicit conversions, which may not be what you want. For example, suppose you define a constructor
for the CBox class like this:

CBox(double side): m_Length(side), m_Width(side), m_Height(side) {}

This is a handy constructor to have when you want to define a CBox object that is a cube, where all the dimensions are the same. Because this constructor has a single parameter, the compiler will use it for implicit conversions when necessary. For example, consider the following code fragment:

1
2
CBox box;
box = 99.0;


The first statement calls the default constructor to create box, so this must be present in the class. The second statement will call the constructor CBox(double) with the argument as 99.0, so you are getting an implicit conversion from a value of type double to type CBox. This may be what you want, but there will be many classes with single argument constructors where you don’t want this to happen.

In these situations, you can use the explicit keyword in the definition of the constructor to prevent it:

explicit CBox(double side): m_Length(side), m_Width(side), m_Height(side) {}"

In this Paragraph of the text:

"The first statement calls the default constructor to create box, so this must be present in the class. The second statement will call the constructor CBox(double) with the argument as 99.0, so you are getting an implicit conversion from a value of type double to type CBox. This may be what you want, but there will be many classes with single argument constructors where you don't want this to happen."

How is the argument implicitly converted to type CBox??? Can anyone explain please? Thanks!
Last edited on Apr 15, 2013 at 3:06am
Apr 15, 2013 at 3:10am
How is the argument implicitly converted to type CBox???


In
1
2
CBox box;
box = 99.0;


A temporary CBox object is created and assigned to Box. It is the equivalent of:

1
2
CBox box ;
box = CBox(99.0);


And, indeed, that is what you must type if the constructor is marked as explicit to make the code work.
Apr 15, 2013 at 3:13am
Oh yes. Since box is a instance of the CBox class the assignment must be of type cbox correct?

Thanks you cleared up my confusion :D
Last edited on Apr 15, 2013 at 3:14am
Apr 15, 2013 at 3:18am
Two last questions though. Why does the compiler only do this for single parameter functions?


Also can you give an example of a situation in which you would not want this to happen please

Thanks :D
Last edited on Apr 15, 2013 at 3:19am
Apr 15, 2013 at 3:35am
Two last questions though. Why does the compiler only do this for single parameter functions?

Can you imagine a way:

1
2
CBox box;
box = ???;


that it would make sense for ??? to implicitly invoke a two-parameter constructor?

Also can you give an example of a situation in which you would not want this to happen please


std::vector has a constructor that takes a single std::size_t parameter that is marked as explicit. If it weren't marked explicit, the following would be legal:

1
2
 std::vector<int> v ;
 v = 6u ;


which doesn't make much sense does it?

Worse, if you had a function that took a const reference to a std::vector, you could feed that function a number:

1
2
3
4
5
6
7
8
9
10
void display(const std::vector<int>& v)
{
    for ( auto it = v.begin(); it != v.end(); ++it )
        std::cout << *it << ' ' ;
}

int main()
{
    display(10u) ;  // this would be legal if the constructor wasn't marked as explicit.
}

Last edited on Apr 15, 2013 at 3:35am
Apr 15, 2013 at 3:45am
@cire

What if the constructor used 2 parameters? Im really confused sorry lol. Trying really hard to understand this and might ask a stupid question or two. Oh nvm I understand it now lol. sorry. Im really sleepy and tired.

Also since I havent used vectors I have no idea what they are. Can you please use a simpler example in order for me to understand? Thanks!
Last edited on Apr 15, 2013 at 3:51am
Apr 15, 2013 at 4:04am
This is a good example right?

You have a MyString(int size) class with a constructor that constructs a string of the given size. You have a function print(MyString &), and you call it with print(3). You expect it to print "3", but it prints an empty string of length 3 instead.
Apr 15, 2013 at 4:33am
This is a good example right?

It works for me.
Apr 15, 2013 at 4:50am
Awesome thanks so much! :D
Apr 15, 2013 at 5:36am
> What if the constructor used 2 parameters?

Since there is more than one parameter, they have to be placed in a braced-init-list. Multiple argument constructors can the be used for implicit conversions, unless they are specified as explicit - the explicit keyword works identically as in the single argument case; it disallows implicit conversions and copy-initializations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A { A() { /*...*/ } A( int, char ) { /*...*/ } } ;
struct B { B() { /*...*/ } explicit B( int, char ) { /*...*/ } } ;

void foo( A ) { /*...*/ }
void bar( B ) { /*...*/ }

int main()
{
    foo( { 123, 'X' } ) ; // fine, implicit conversion to A
    A a ;
    a = { 123, 'X' } ; // fine, implicit conversion to A

    bar( { 123, 'X' } ) ; // **** error, no implicit conversion to B
    B b ;
    b = { 123, 'X' } ; // **** error, no implicit conversion to B

}


Though, the rationale for specifying a multiple argument constructor as explicit is much weaker. For a single argument constructor, "the principle of least surprise" is applicable; it is far less likely that a programmer who uses a braced-init-list would be surprised by an implicit conversion.
Apr 16, 2013 at 3:53am
Since there is more than one parameter, they have to be placed in a braced-init-list.


Good call. That slips my mind since I generally use VC++ and it isn't well supported there, so I generally avoid it.

Thanks!
Topic archived. No new replies allowed.