operator=() in base and derived class

Discussion in 'C++' started by MWimmer, Oct 22, 2007.

  1. MWimmer

    MWimmer Guest

    Dear members of this group,

    recently I came across a problem with repsect to operator=() and
    inheritance. Consider the following code snippet:

    ------------------------------------------------------------
    #include <iostream>

    using namespace std;

    class A
    {
    public:
    A & operator=(const A &_a) {
    cout << " in A" << endl;
    }
    };

    class B : public A
    {
    public:
    B & operator=(const A &_a) {
    cout << " in B" << endl;
    A::eek:perator=(_a);
    }
    };

    main()
    {
    B b1, b2;
    A a;

    b1=b2;

    cout << endl;

    b1=a;
    }
    ----------------------------------------

    If you run this program (compiled using gcc 3.3 and 4.1), the output
    you get is:

    -------------------
    in A

    in B
    in A
    ------------------

    This means:
    * for the assignment b1=b2, A::eek:perator=() is invoked
    * for b1=a, B::eek:perator=() is invoked.

    Now the solution to make the code behave as intended by me is to add
    another function

    B & operator=(const B&_B) {
    cout << " in B" << endl;
    A::eek:perator=(_b);
    }

    However, I don't understand the reasons for this behaviour and I'd
    like to understand that. What are the rationales behind that behaviour?
    MWimmer, Oct 22, 2007
    #1
    1. Advertising

  2. MWimmer

    Uday Bidkar Guest

    In b1=b2, since you haven't provided an operator =() in class B that
    takes an object of B, you get a default one from compiler which would
    do bitwise copy of B's members. Since you have provided an operator
    =() in A, the compiler generated operator =() calls this one to copy
    A's members. Hence you see a call to A::eek:perator=().

    In b1=a, you have your own operator =() that takes object of class A
    and hence this is the function that gets called.

    -Uday Bidkar
    MWimmer wrote:

    > Dear members of this group,
    >
    > recently I came across a problem with repsect to operator=() and
    > inheritance. Consider the following code snippet:
    >
    > ------------------------------------------------------------
    > #include <iostream>
    >
    > using namespace std;
    >
    > class A
    > {
    > public:
    > A & operator=(const A &_a) {
    > cout << " in A" << endl;
    > }
    > };
    >
    > class B : public A
    > {
    > public:
    > B & operator=(const A &_a) {
    > cout << " in B" << endl;
    > A::eek:perator=(_a);
    > }
    > };
    >
    > main()
    > {
    > B b1, b2;
    > A a;
    >
    > b1=b2;
    >
    > cout << endl;
    >
    > b1=a;
    > }
    > ----------------------------------------
    >
    > If you run this program (compiled using gcc 3.3 and 4.1), the output
    > you get is:
    >
    > -------------------
    > in A
    >
    > in B
    > in A
    > ------------------
    >
    > This means:
    > * for the assignment b1=b2, A::eek:perator=() is invoked
    > * for b1=a, B::eek:perator=() is invoked.
    >
    > Now the solution to make the code behave as intended by me is to add
    > another function
    >
    > B & operator=(const B&_B) {
    > cout << " in B" << endl;
    > A::eek:perator=(_b);
    > }
    >
    > However, I don't understand the reasons for this behaviour and I'd
    > like to understand that. What are the rationales behind that behaviour?
    Uday Bidkar, Oct 22, 2007
    #2
    1. Advertising

  3. MWimmer

    wyg Guest

    On Oct 22, 4:44 pm, MWimmer <> wrote:
    > Dear members of this group,
    >
    > recently I came across a problem with repsect to operator=() and
    > inheritance. Consider the following code snippet:
    >
    > ------------------------------------------------------------
    > #include <iostream>
    >
    > using namespace std;
    >
    > class A
    > {
    > public:
    > A & operator=(const A &_a) {
    > cout << " in A" << endl;
    > }
    >
    > };
    >
    > class B : public A
    > {
    > public:
    > B & operator=(const A &_a) {
    > cout << " in B" << endl;
    > A::eek:perator=(_a);
    > }
    >
    > };
    >
    > main()
    > {
    > B b1, b2;
    > A a;
    >
    > b1=b2;
    >
    > cout << endl;
    >
    > b1=a;}
    >
    > ----------------------------------------
    >
    > If you run this program (compiled using gcc 3.3 and 4.1), the output
    > you get is:
    >
    > -------------------
    > in A
    >
    > in B
    > in A
    > ------------------
    >
    > This means:
    > * for the assignment b1=b2, A::eek:perator=() is invoked
    > * for b1=a, B::eek:perator=() is invoked.
    >
    > Now the solution to make the code behave as intended by me is to add
    > another function
    >
    > B & operator=(const B&_B) {
    > cout << " in B" << endl;
    > A::eek:perator=(_b);
    > }
    >
    > However, I don't understand the reasons for this behaviour and I'd
    > like to understand that. What are the rationales behind that behaviour?


    I copied some information from MSDN for you reference:
    The assignment operator has some additional restrictions. It can be
    overloaded only as a nonstatic member function, not as a friend
    function. It is the only operator that cannot be inherited; a derived
    class cannot use a base class's assignment operator.
    wyg, Oct 22, 2007
    #3
  4. MWimmer

    MWimmer Guest

    On Oct 22, 11:24 am, Uday Bidkar <> wrote:
    > In b1=b2, since you haven't provided an operator =() in class B that
    > takes an object of B, you get a default one from compiler which would
    > do bitwise copy of B's members. Since you have provided an operator
    > =() in A, the compiler generated operator =() calls this one to copy
    > A's members. Hence you see a call to A::eek:perator=().
    >
    > In b1=a, you have your own operator =() that takes object of class A
    > and hence this is the function that gets called.
    >
    > -Uday Bidkar


    Ah, thanks a lot, that makes it clear!
    MWimmer, Oct 22, 2007
    #4
  5. MWimmer

    Lance Diduck Guest

    On Oct 22, 4:44 am, MWimmer <> wrote:
    > Dear members of this group,
    >
    > recently I came across a problem with repsect to operator=() and
    > inheritance. Consider the following code snippet:
    >
    > ------------------------------------------------------------
    > #include <iostream>
    >
    > using namespace std;
    >
    > class A
    > {
    > public:
    > A & operator=(const A &_a) {
    > cout << " in A" << endl;
    > }
    >
    > };
    >
    > class B : public A
    > {
    > public:
    > B & operator=(const A &_a) {
    > cout << " in B" << endl;
    > A::eek:perator=(_a);
    > }
    >
    > };
    >
    > main()
    > {
    > B b1, b2;
    > A a;
    >
    > b1=b2;
    >
    > cout << endl;
    >
    > b1=a;}
    >
    > ----------------------------------------
    >
    > If you run this program (compiled using gcc 3.3 and 4.1), the output
    > you get is:
    >
    > -------------------
    > in A
    >
    > in B
    > in A
    > ------------------
    >
    > This means:
    > * for the assignment b1=b2, A::eek:perator=() is invoked
    > * for b1=a, B::eek:perator=() is invoked.
    >
    > Now the solution to make the code behave as intended by me is to add
    > another function
    >
    > B & operator=(const B&_B) {
    > cout << " in B" << endl;
    > A::eek:perator=(_b);
    > }
    >
    > However, I don't understand the reasons for this behaviour and I'd
    > like to understand that. What are the rationales behind that behaviour?


    The compiler will implicily create an assignment operator, that just
    calls assignment for member and base.
    The only way not to get this is to define one yourself, that takes the
    type as an argument. In this case, B&operator=(A const&); does not
    turn off this implictly generated function.

    The complier made up a function for you that looks like
    B&operator=(B const&b){
    A::eek:perator=(b);
    }


    Why does it do this? This is more to support some coding styles that
    are essentially mixtures of C and C++. So in C we may have

    struct A{
    int g;
    char buf[123];
    };
    struct B{
    A a;//C version of inheritance
    double d[543];
    };
    void foo(){
    struct B b1,b2;
    b1=b2;//C does a implicit memcpy underneath the hood

    }
    So you can see that the "implicit operator=" is a holdover from C.
    when this is converted to C++, it may look like

    struct A1{
    int g;
    std::string buf;
    };
    struct B1:A1{
    std::vector<double> d;
    };

    void foo1(){
    struct B1 b1,b2;
    b1=b2;//C++ does a member by member operator= underneath the hood
    //because string and vector will not survive a memcpy
    }



    Lance
    Lance Diduck, Oct 22, 2007
    #5
  6. MWimmer

    anon Guest

    My comment will not change behavior of your classes, but aren't you
    missing something here?

    MWimmer wrote:
    > class A
    > {
    > public:
    > A & operator=(const A &_a) {
    > cout << " in A" << endl;

    return *this;
    > }
    > };
    >
    > class B : public A
    > {
    > public:
    > B & operator=(const A &_a) {
    > cout << " in B" << endl;
    > A::eek:perator=(_a);

    return *this;
    > }
    > };
    >
    anon, Oct 22, 2007
    #6
  7. MWimmer

    MWimmer Guest

    On Oct 22, 11:44 am, anon <> wrote:
    > My comment will not change behavior of your classes, but aren't you
    > missing something here?
    >
    >
    >
    > MWimmer wrote:
    > > class A
    > > {
    > > public:
    > > A & operator=(const A &_a) {
    > > cout << " in A" << endl;

    > return *this;
    > > }
    > > };

    >
    > > class B : public A
    > > {
    > > public:
    > > B & operator=(const A &_a) {
    > > cout << " in B" << endl;
    > > A::eek:perator=(_a);

    > return *this;
    > > }
    > > };


    Yes I did miss the return *this - I forgot to add it in this made up
    example.

    Thanks guys, you've been very helpful, now i understand the problem :)
    MWimmer, Oct 22, 2007
    #7
  8. MWimmer

    James Kanze Guest

    On Oct 22, 11:24 am, Uday Bidkar <> wrote:
    > In b1=b2, since you haven't provided an operator =() in class B that
    > takes an object of B, you get a default one from compiler which would
    > do bitwise copy of B's members.


    Not quite. The default operator= does a memberwise copy.
    (Otherwise, he wouldn't have seen the message from the operator=
    of the base class.) But you're right concerning the important
    point here: unless you explicitly declare a "copy assignment"
    operator=, the compiler implicitly generates one.

    And just for completeness' sake, I'll add that a function
    template operator= is never considered "copy assignment", and
    will never prevent the compiler from generating its version.

    > Since you have provided an operator
    > =() in A, the compiler generated operator =() calls this one to copy
    > A's members. Hence you see a call to A::eek:perator=().


    And if he hadn't provided it, of course, the assignment would
    have been illegal.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Oct 23, 2007
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Alicia
    Replies:
    3
    Views:
    927
    jjr2004a
    Nov 24, 2004
  2. Replies:
    4
    Views:
    393
    Alf P. Steinbach
    May 23, 2007
  3. Replies:
    1
    Views:
    387
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    375
    Victor Bazarov
    May 23, 2007
  5. Replies:
    2
    Views:
    695
Loading...

Share This Page