Sign in to follow this  
discman1028

C++ Constructor Arcane-ness :)

Recommended Posts

Hey all, I had never seen this C++ feature before until someone mentioned it the other day:
class A;
class B;

void main()
{
   B obj("hello");  // This actually calls B::B(A::A("hello"))
}
class B
{
   B(A obj) { ... }
};
class A
{
   A(char * str) { ... }
};
This example might not be syntactically correct, but it's the idea. Anyone actually use this for something useful? (What is a use?) discman1028

Share this post


Link to post
Share on other sites
It's kind of a side effect of something else entirely.

Constructors that take a single argument and aren't marked as explicit get used for implicit type conversions. That is, due to A's constructor, the compiler now knows how to automatically turn a character pointer into an A object.

In your example, B's constructor expects and A object, but you pass a character pointer. The compiler knows how to create an A object from a character pointer, so it does the conversion for you, so it works.

It doesn't have to be a constructor; it will automatically convert types for all functions and operators if the types aren't what it expects, and there is only one possible way to do it; otherwise it will complain about ambiguity.

It is a useful feature, it can save you writing code for every possible way something might be used, or having to cast everything to the proper type. It can also be an unobvious way to lose performance, because functions are going to end up being called and objects created that isn't obvious when you look at the code.

Share this post


Link to post
Share on other sites
Thanks!

Quote:
Original post by smart_idiot
It can also be an unobvious way to lose performance, because functions are going to end up being called and objects created that isn't obvious when you look at the code.


Though, it would only be unobvious that an object is being created if the programmer used this methodology by accident. Then again, I guess they could know the feature without knowing what's going on, too.

Share this post


Link to post
Share on other sites
Quote:
Original post by bballmitch
umm...I see how that works, but I can't think of ANY situation where that would be useful. :(


How about this.

struct Point
{
Point(double x, double y)
: m_x(x), m_y(y)
{ }

double m_x;
double m_y;
}

Point origin(0, 0);


Wouldn't you be surprized if that didn't compile?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Just thought I would add how you can prevent that behaviour as it's not always desirable.


class A;
class B;

void main()
{
B obj("hello"); // Error, A::A(char*) is marked explicit
}



class B
{
B(A obj) { ... }
};



class A
{
explicit A(char * str) { ... }
};

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma
Quote:
Original post by bballmitch
umm...I see how that works, but I can't think of ANY situation where that would be useful. :(


How about this.

struct Point
{
Point(double x, double y)
: m_x(x), m_y(y)
{ }

double m_x;
double m_y;
}

Point origin(0, 0);


Wouldn't you be surprized if that didn't compile?


I would have been surprised if that compiled, since no constructor is made for type double! I did not know that was possible. I would be less surprised, in this shown case though, since I can understand implicit casting from int to double. But from a POD (plain old datatype) to an object, via a constructor, I was surprised.

By the way, I believe this property may only be "nested" a couple times (only a couple constructor levels down). I haven't tested it, it's just whaty I heard from my source.

@Anonymous Poster: Yep, that 'explicit' keyword is good to know! Thanks to the posters here for letting me know about it!

Share this post


Link to post
Share on other sites
Ah, but there is, although I don't know if it officially is a constructor. That is why the following code works.


#include <iostream>

using namespace std;

int main(void)
{
double d(4.5);
int i(3);

cout << "d = " << d << ", i = " << i << endl;
return 0;
}

Share this post


Link to post
Share on other sites
Quote:
I would have been surprised if that compiled, since no constructor is made for type double!


There is an implicit promotion from int to double. This code should compile.

I did not know that was possible. I would be less surprised, in this shown case though, since I can understand implicit casting from int to double.

Quote:
But from a POD (plain old datatype) to an object, via a constructor, I was surprised.


Single parameter constructors are known as conversion constructors. They are the counterpart of conversion operators.

Quote:
By the way, I believe this property may only be "nested" a couple times (only a couple constructor levels down).


The implicit conversion chain can only contain one user-defined conversion.

Quote:
@Anonymous Poster: Yep, that 'explicit' keyword is good to know! Thanks to the posters here for letting me know about it!


Single-parameter constructors should be marked explicit unless you know you want them to act as conversion constructors.

Share this post


Link to post
Share on other sites
Quote:
Original post by discman1028
I can understand implicit casting from int to double. But from a POD (plain old datatype) to an object, via a constructor, I was surprised.


There is no implicit cast from int to double. There is an implicit type conversion, though. A cast and a type conversion are two different things. Perhaps that's why you're surprized.

One of the guiding principals in C++ is "what would int do?" (WWID). Okay, so maybe I just made up that expression, but the pricipal is there. In the example I gave, the int is automatically converted to a double. It would be the same if there was a conversion constructor for a non-pod type. Do what the ints do.

The overload resolution rules are, in order:

(1) exact match

(2) match using a promotion (eg. bool to int, flot to double, etc)

(3) match using a standard conversion (eg. int to double, Derived* to Base*, etc)

(4) match using user-defined conversion (conversion constructor, cast operator())

(5) match using the ellipsis


More than one match at the same level is an ambiguity error.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by Bregma
"what would int do?" (WWID)


I believe "Do as the ints do" is more common, but yours is certainly more amusing [grin]

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma
Quote:
Original post by discman1028
I can understand implicit casting from int to double. But from a POD (plain old datatype) to an object, via a constructor, I was surprised.


There is no implicit cast from int to double. There is an implicit type conversion, though. A cast and a type conversion are two different things. Perhaps that's why you're surprized.


Nope that's not why, I meant implicit conversion, but used "cast" lazily. Just surprized b/c I've never seen it before.

Quote:
Original post by Fruny
Quote:

I would have been surprised if that compiled, since no constructor is made for type double!



There is an implicit promotion from int to double. This code should compile.


Let's just say, I would have been surprised 48 hours ago...


Thanks all!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this