C++ Constructor Arcane-ness :)

Started by
12 comments, last by discman1028 18 years, 1 month ago
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
--== discman1028 ==--
Advertisement
Probably so things like this don't generate errors:
#include <string>int main() {    A a("example");    ...}struct A {    A(std::string string) { ... }    ...};
umm...I see how that works, but I can't think of ANY situation where that would be useful. :(
Mitchen Games
Ah! That's a good one I never thought about. :) (@Roboguy)
--== discman1028 ==--
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.
Chess is played by three people. Two people play the game; the third provides moral support for the pawns. The object of the game is to kill your opponent by flinging captured pieces at his head. Since the only piece that can be killed is a pawn, the two armies agree to meet in a pawn-infested area (or even a pawn shop) and kill as many pawns as possible in the crossfire. If the game goes on for an hour, one player may legally attempt to gouge out the other player's eyes with his King.
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.
--== discman1028 ==--
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?

Stephen M. Webb
Professional Free Software Developer

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) { ... }
};

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!
--== discman1028 ==--
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;}

This topic is closed to new replies.

Advertisement