Issue
Let's say we have 2 classes :
class base{
protected:
char first_name;
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, base &client1)
{
char f_name[1001];
cout << "First Name: ";
in >> f_name;
client1=base(f_name); /// class parameterised constructor;
return in;
}
};
class derived: public base{
protected:
char last_name[1001];
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, derived &client2)
{
char l_name[1001], f_name[1001];
in >> (base) client2; /// it's not working like it dose in operator<<..
cout << "Last Name: ";
is >> l_name;
client2=derived(f_name, l_name); /// class parameterized constructor, 2 parameters because it use base constructor as well;
return in;
}
};
I overloaded some output operators (<<) and it seems to do fine every time i call the operator<< from base in derived operator<<.
I don't know if this works the same for operator<<, i tried something but it gives an error. When i call base class operator>> inside derived class operator>> it gives me error :
" no matching function for call to 'operator>>(std::istream&, abonament)'| "
Again, if i do the same thing in operator<< , it's working fine :
friend ostream& operator << (ostream& out, derived &client)
{
out << (base) client; /// it's working;
out << client.last_name;
return in;
}
Is it possible to call base class operator>> inside derived class operator>> > Why is this happening and how to solve it ? ( i hope i don't have to rewrite the same lines from base class operator>> again in derived class operator>> )
Solution
You have fallen prey to object slicing. You can fix the immediate problem by casting to a reference.
In
in >> (base) client2;
what's really happening is a new temporary Base
is made from client2
, discarding all of derived
's added members. This is legal. The compiler gets upset because the temporary Base
cannot be used as an argument to a base &client1
parameter. Temporary variables are just like they sound. They aren't around long, so taking a reference to one is a mistake the compiler is preventing you from making. If it were legal, the temporary variable would be modified by Base
's >>
operator and then immediately go out of scope before you could use what was read into it.
in >> (base&) client2;
does not slice and does not make a temporary variable. client2
is successfully updated. Unfortunately this work is thrown away when
client2=derived(f_name, l_name);
writes over it with the uninitialized variable l_name
.
So more changes are needed.
Do not use constructors to completely recreate and reassign the objects you're reading into. Instead read directly into the object's member variables.
Example:
class base{
protected:
char first_name[1001]; // need more than one character
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, base &client1)
{
// char f_name[1001]; don't need. Read into member
cout << "First Name: ";
in >> client1.first_name; // read directly into member
// client1=base(f_name); don't need. Work done above
return in;
}
};
class derived: public base{
protected:
char last_name[1001];
public:
/// constructors , destructor, operator= overloading ...
friend istream& operator >> (istream& in, derived &client2)
{
//char l_name[1001], f_name[1001]; don't need. Use member variables
in >> (base&) client2; // client was being sliced. explanatory link above
// ^ fixed with reference to allow polymorphism
cout << "Last Name: ";
in >> client2.last_name; // fixed typo. reading directly into member
// client2=derived(f_name, l_name); don't need. Work done above
return in;
}
};
Side note: This is a misuse of inheritance. Effectively this is saying that a last name is-a first name. Which it isn't. Read up on the Liskov Substitution principle for a good rule to help determine when inheritance makes sense. Here's some starter reading: What is an example of the Liskov Substitution Principle?
Side Note: >>
reads one whitespace-delimited token, one word, into the given char
array. There are two problems here. The most important is it doesn't know when to stop. This is only partially mitigated by the 1001 character array. The user needs to type for a long time to overflow the buffer, but do not doubt that people will do it for fun or profit. Use std::string
instead and that problem goes away. The second problem is the whole one word thing. This parser cannot handle Names like "Billy Bob" or "von Doom", and it's fortunate the owner of that last name is fictional as he's well-known to be unforgiving.
Answered By - user4581301 Answer Checked By - Gilberto Lyons (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.