conversion constructor called twice - why?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Alexander Stippler

    conversion constructor called twice - why?

    Given the following code snippet we get some unexpected behaviour:
    //--------------------------------------------------------------------
    #include <iostream>

    using namespace std;

    struct A
    {
    A() { cerr << "A()" << endl; }
    };

    struct C;

    struct B : public A
    {
    B();

    explicit
    B(const B &rhs);

    B(const A&rhs);

    C
    operator()(int from, int to);
    };

    struct C: public A
    {
    B r;

    operator const B &() const;
    };

    B::B() { cerr << "B()" << endl; }

    B::B(const B &rhs)
    { cerr << "B(const B &rhs)" << endl; }

    B::B(const A &rhs)
    { cerr << "B(const A &rhs)" << endl; }

    C
    B::operator()(i nt from, int to) { return C(); }

    C::operator const B &() const
    { cerr << "operator const B &() const" << endl;
    return r;
    }

    int main()
    {
    C c;
    B b = c; // conversion constructor called twice here - why??
    return 0;
    }
    //--------------------------------------------------------------------

    The conversion constructor B(const A &) is called twice when
    initializing object b. We would expect a call of
    C::operator const B &() const
    and then one call of
    B::B(const B &).


  • Valentin Samko

    #2
    Re: conversion constructor called twice - why?

    Alexander Stippler wrote:[color=blue]
    > struct B : public A
    > {
    > explicit
    > B(const B &rhs);
    >
    > B(const A&rhs);
    >
    > };[/color]
    [color=blue]
    > B b = c; // conversion constructor called twice here - why??[/color]
    [color=blue]
    > The conversion constructor B(const A &) is called twice when
    > initializing object b. We would expect a call of
    > C::operator const B &() const
    > and then one call of
    > B::B(const B &).[/color]

    The call to B::B(const B&) is not happening because that copy constructor is explicit.

    Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".

    Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
    1. "c" is casted to A&
    2. a temporary of class B is created from the result via the "B(const A&)" constructor.
    3. your "b" is initialised with that temporary.

    --

    Valentin Samko - http://www.valentinsamko.com

    Comment

    • Greg

      #3
      Re: conversion constructor called twice - why?


      Valentin Samko wrote:[color=blue]
      > Alexander Stippler wrote:[color=green]
      > > struct B : public A
      > > {
      > > explicit
      > > B(const B &rhs);
      > >
      > > B(const A&rhs);
      > >
      > > };[/color]
      >[color=green]
      > > B b = c; // conversion constructor called twice here - why??[/color]
      >[color=green]
      > > The conversion constructor B(const A &) is called twice when
      > > initializing object b. We would expect a call of
      > > C::operator const B &() const
      > > and then one call of
      > > B::B(const B &).[/color]
      >
      > The call to B::B(const B&) is not happening because that copy constructor is explicit.
      >
      > Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".
      >
      > Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
      > 1. "c" is casted to A&
      > 2. a temporary of class B is created from the result via the "B(const A&)" constructor.
      > 3. your "b" is initialised with that temporary.[/color]

      No, there is no temporary. Two user-defined conversions would be one
      more than is allowed. Besides, there is no need of a B temporary since
      B has a constructor that accepts an A object directly. So b is
      constructed from an A class object (namely, c).

      Greg

      Comment

      • Valentin Samko

        #4
        Re: conversion constructor called twice - why?

        Greg wrote:[color=blue]
        > Valentin Samko wrote:[color=green]
        >> Alexander Stippler wrote:[color=darkred]
        >>> struct B : public A
        >>> {
        >>> explicit
        >>> B(const B &rhs);
        >>>
        >>> B(const A&rhs);
        >>>
        >>> };
        >>> B b = c; // conversion constructor called twice here - why??
        >>> The conversion constructor B(const A &) is called twice when
        >>> initializing object b. We would expect a call of
        >>> C::operator const B &() const
        >>> and then one call of
        >>> B::B(const B &).[/color]
        >> The call to B::B(const B&) is not happening because that copy constructor is explicit.
        >>
        >> Regarding calling this constructor twice - See 8.5/14 "Otherwise (i.e. for the remaining...".
        >>
        >> Since your copy constructor in B is explicit, so the compiler chooses another path, i.e.
        >> 1. "c" is casted to A&
        >> 2. a temporary of class B is created from the result via the "B(const A&)" constructor.
        >> 3. your "b" is initialised with that temporary.[/color]
        >
        > No, there is no temporary. Two user-defined conversions would be one
        > more than is allowed. Besides, there is no need of a B temporary since
        > B has a constructor that accepts an A object directly. So b is
        > constructed from an A class object (namely, c).[/color]

        Please read 8.5/14. The right hand side has to be converted to the destination type (B)
        first. Only after the rhs is converted, compiler picks the most appropriate constructor.

        Besides, no used-defined conversions happen.

        --

        Valentin Samko - http://www.valentinsamko.com

        Comment

        Working...