operator overloading in the derived class could not work...

Discussion in 'C++' started by wfhsiao@libra.seed.net.tw, Apr 13, 2006.

  1. Guest

    Hello,

    while refreshing my understanding of C++, I found the overloaded
    operators could not work properly. Why my following codes keep printing
    the student b's data as a person's? Did I lost anything? Thanks for
    your help!

    person a("John", 30);
    student b("Mary", 20, "93406001");
    person *p[2] = {&a, &b};
    for (int j=0; j<2; j++)
    cout << (*p[j]+3) << endl;

    The definitions of person and student are listed below.
    --------------------------------
    class person
    {
    private:
    string name;
    int age;
    public:
    person(string na, int ag):name(na), age(ag) {}
    person operator+(int n) const
    {
    return person(name, age+n);
    }
    virtual void print(ostream& os) const
    {
    os << name << " " << age;
    }
    };

    ostream& operator<< (ostream& os, const person &aP)
    {
    aP.print(os);
    return os;
    }
    -----------------------------------
    class student:public person
    {
    private:
    string studentNo;
    public:
    student(string na, int ag, string sno):person(na, ag), studentNo(sno)
    {}
    void print(ostream &os) const
    {
    os << studentNo << " ";
    person::print(os);
    }
    };
    , Apr 13, 2006
    #1
    1. Advertising

  2. Heinz Ozwirk Guest

    <> schrieb im Newsbeitrag news:...
    > Hello,
    >
    > while refreshing my understanding of C++, I found the overloaded
    > operators could not work properly. Why my following codes keep printing
    > the student b's data as a person's? Did I lost anything? Thanks for
    > your help!
    >
    > person a("John", 30);
    > student b("Mary", 20, "93406001");
    > person *p[2] = {&a, &b};
    > for (int j=0; j<2; j++)
    > cout << (*p[j]+3) << endl;

    ....

    What does the program print and what do you expect?

    Heinz
    Heinz Ozwirk, Apr 13, 2006
    #2
    1. Advertising

  3. Guest

    Obviously I would like to see the corresponding print function be
    issued. Since p[0] refers to a person object, while p[1], a student
    object. The result should reasonably be as follows:
    John 33
    93406001 Mary 23

    However, it is quite frustrated. The result it printed out is
    John 33
    Mary 23

    So my question is how to make "the operator+" work as what I want?
    , Apr 13, 2006
    #3
  4. Heinz Ozwirk Guest

    <> schrieb im Newsbeitrag news:...
    > Obviously I would like to see the corresponding print function be
    > issued. Since p[0] refers to a person object, while p[1], a student
    > object. The result should reasonably be as follows:
    > John 33
    > 93406001 Mary 23
    >
    > However, it is quite frustrated. The result it printed out is
    > John 33
    > Mary 23
    >
    > So my question is how to make "the operator+" work as what I want?


    [Code from original post]
    > person a("John", 30);
    > student b("Mary", 20, "93406001");
    > person *p[2] = {&a, &b};
    > for (int j=0; j<2; j++)
    > cout << (*p[j]+3) << endl;
    >
    > The definitions of person and student are listed below.
    > --------------------------------
    > class person
    > {
    > private:
    > string name;
    > int age;
    > public:
    > person(string na, int ag):name(na), age(ag) {}
    > person operator+(int n) const
    > {
    > return person(name, age+n);
    > }


    operator+ creates a new object of type person. It doesn't matter that the object for which it has been called is of a derived type. Your code tells the compiler to return a person, not a student, so you get what you asked for. If you want operator+ to behave differently for objects of type student, you have to implement it for class student, too. Without it the compiler does not lnow how to add an int to a student. It only knows that students are persons, too, and how to add an int to a person, and it knows that the result of such an operation is a person, but not a student. Actually, when compiling class person, it doesn't even know that there is such a thing as a student.

    HTH
    Heinz
    Heinz Ozwirk, Apr 13, 2006
    #4
  5. Guest

    Yes. This is a reasonable conjecture, and I tried it before but in
    vain. (Sorry for not providing all these information at the very
    beginning, 'cause I thought you might ever encounter and solve such
    questions.)

    I added the following code to the student class, and modified the
    access modifier of name and age in person from private to protected,
    accordingly.
    student operator+(int n) const
    {
    return student(name, age+n, studentNo);
    }

    The printed result is still the same.
    > John 33
    > Mary 23
    , Apr 14, 2006
    #5
  6. Guest

    Thanks! Your first method can work. However, it has the drawback of
    side-effect: the object's content has been modified. Is there any other
    way? The second method, using friend, could not work, even when I
    define such a friend function for student class.
    , Apr 14, 2006
    #6
  7. dan2online Guest

    > The second method, using friend, could not work, even when I
    > define such a friend function for student class.


    You need a copy constructor. Try it.
    dan2online, Apr 14, 2006
    #7
  8. Guest

    Nope, I have tried it, but it still did not work. (Here to work means
    it can successfully print out the student object's data; the proposed
    friend function can only print out person's data). Should I declare the
    operator+ as a virtual function as below? But obviously it won't work
    since the derived class could not overwrite it, since their return
    types are different. Could someone give me more hints?

    class person
    {
    public:
    virtual person operator+(int n) const
    {
    return person(name, age+n);
    }
    };

    class student: public person
    {
    public:
    virtual student operator+(int n) const
    {
    return student(name, age+n, studentNo);
    }
    };
    , Apr 14, 2006
    #8
  9. wrote:
    > Nope, I have tried it, but it still did not work. (Here to work means
    > it can successfully print out the student object's data; the proposed
    > friend function can only print out person's data). Should I declare
    > the operator+ as a virtual function as below? But obviously it won't
    > work since the derived class could not overwrite it, since their
    > return types are different. Could someone give me more hints?
    >
    > class person
    > {
    > public:
    > virtual person operator+(int n) const
    > {
    > return person(name, age+n);
    > }
    > };
    >
    > class student: public person
    > {
    > public:
    > virtual student operator+(int n) const
    > {
    > return student(name, age+n, studentNo);
    > }
    > };


    That wouldn't compile. The return value has to be covariant.

    I think 'dan2online's suggestion about making your operator + return
    a reference has merit.

    The main question here is, why do you want to have it as an operator?
    Couldn't you use a normal (named) function? The problem, of course,
    is that you cannot follow both the recommendation that operator + must
    return an object and that virtual functions need to have covariant
    returns, _without_ creating some kind of proxy object and building
    other things around it. If you just allow your operator+ return
    a reference to 'person', your problems should go away.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Apr 14, 2006
    #9
  10. Tom Guest

    Actually, I tried some other solutions, and I guess using += and
    clone() might be the best way to avoid this problem.
    //---------------------------------------------------------------------------------------
    class person
    {
    protected:
    string name;
    int age;

    public:
    person(string na, int ag):name(na), age(ag) {}

    virtual person* clone() const
    {
    return (new person(name, age));
    }

    virtual person& operator += (int n)
    {
    age += n;
    return *this;
    }

    virtual void print(ostream& os) const
    {
    os << name << " " << age;
    }
    };

    ostream& operator<< (ostream& os, const person &aP)
    {
    aP.print(os);
    return os;
    }

    class student : public person
    {
    string studentNo;

    public:
    student(string na, int ag, string sno):person(na, ag),
    studentNo(sno)
    {}

    virtual person* clone() const
    {
    return (new student(name, age, studentNo));
    }

    void print(ostream &os) const
    {
    os << studentNo << " ";
    person::print(os);
    }
    };

    int main()
    {
    student s("student", 20, "1000");
    std::auto_ptr<person> sp(s.clone());
    std::cout << (*sp += 3) << std::endl;
    }
    Tom, Apr 17, 2006
    #10
  11. dan2online Guest

    wrote:
    > Nope, I have tried it, but it still did not work. (Here to work means
    > it can successfully print out the student object's data; the proposed
    > friend function can only print out person's data). Should I declare the
    > operator+ as a virtual function as below? But obviously it won't work
    > since the derived class could not overwrite it, since their return
    > types are different. Could someone give me more hints?
    >
    > class person
    > {
    > public:


    What you want to do equal to the assignment " person2 = person1 +
    age_addition", right ?

    So you need (1) default constructor (2) copy constructor (3) friend
    function for operatotr +

    > virtual person operator+(int n) const
    > {
    > return person(name, age+n);


    person(name, age+n) is live only in the scope of the function inside,
    the local object will be deleted when out of the scope. In order to
    keep the local object life, you can define it as a static object;

    ==================================
    FYI, you can test the following code:
    ==================================
    #include <iostream>
    #include <string>


    using namespace std;

    class person
    {
    protected:
    string name;
    int age;

    public:

    person() :name(""), age(0){}

    person(string na, int ag):name(na), age(ag) {}

    person(const person& p);

    friend person& operator+(const person&, int n);

    virtual void print(ostream& os) const
    {
    os << name << " " << age;
    }

    };

    person::person(const person& p)
    {
    name = p.name;
    age = p.age;
    }

    person& operator+ (const person &p, int n)
    {
    static person default_person;
    default_person.name = p.name;
    default_person.age = p.age + n;
    return default_person;
    }

    ostream& operator<< (ostream& os, const person &aP)
    {
    aP.print(os);
    return os;

    }

    int main()
    {
    person p("student", 20);
    cout << p << endl;
    cout << p + 5 << endl;
    cout << p << endl;
    return 0;
    }
    dan2online, Apr 17, 2006
    #11
    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. Gerhard Pfeiffer
    Replies:
    3
    Views:
    413
    Victor Bazarov
    Sep 14, 2006
  3. Replies:
    1
    Views:
    387
    myork
    May 23, 2007
  4. Replies:
    1
    Views:
    374
    Victor Bazarov
    May 23, 2007
  5. David
    Replies:
    3
    Views:
    393
    Grizlyk
    Jan 29, 2008
Loading...

Share This Page