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

W

wfhsiao

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);
}
};
 
H

Heinz Ozwirk

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
 
W

wfhsiao

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?
 
H

Heinz Ozwirk

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
 
W

wfhsiao

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.
 
W

wfhsiao

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.
 
W

wfhsiao

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);
}
};
 
V

Victor Bazarov

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
 
T

Tom

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;
}
 
D

dan2online

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;
}
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top