May I please have some help!

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
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.
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
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
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
@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
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.
This is a good example right?

It works for me.
Awesome thanks so much! :D
> 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.
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.