Here are the instructions verbatim:
String insertion/extraction operators (<< and >>) need to be overloaded within the MyString object. These operators will also need to be capable of cascaded operations (i.e., cout << String1 << String2 or cin >> String1 >> String2). The string insertion operator (>>) will read an entire line of characters that is either terminated by an end-of-line character (\n) or 256 characters long. An input line that exceeds 256 characters will be limited to only the first 256 characters.
With that, this is the code I've gotten thus far:
in my .cpp file:
istream& MyString::operator>>(istream& input, MyString& rhs)
{
char* temp;
int size(256);
temp = new char[size];
input.get(temp,size);
rhs = MyString(temp);
delete [] temp;
return input;
}
in my .h file:
istream& operator>>(istream& input, MyString& rhs);
call from main.cpp file:
MyString String1;
const MyString ConstString("Target string"); //Test of alternate constructor
MyString SearchString; //Test of default constructor that should set "Hello World"
MyString TargetString (String1); //Test of copy constructor
cout << "Please enter two strings. ";
cout << "Each string needs to be shorter than 256 characters or terminated by
/.\n" << endl;
cout << "The first string will be searched to see whether it contains exactly the second string. " << endl;
cin >> SearchString >> TargetString; // Test of cascaded string-extraction operator<<
The error that I get is: istream& MyString::operator>>(std::istream&, MyString&)â must take exactly one argument
How can I correct this? I am super confused on how to do this without BOTH the rhs and input
You have to create the operator>> as a non-member function.
As it is now, your function expects three arguments: the implicit invoking object, the istream&, and the MyString& rhs. However, since operator>> is a binary operator (it takes exactly two arguments) this won't work.
The way to do this is to make it a non-member function:
// prototype, OUTSIDE the class definition
istream& operator>>(istream&, MyString&);
// implementation
istream& operator>>(istream& lhs, MyString& rhs) {
// logic
return lhs;
}
And doing it that way (non-member function) is the way you have to do all operators where you want your class to be on the right side, and a class that you can't modify on the left side.
Also note that if you want to have that function access private or protected members of your objects, you have to declare it friend in your class definition.
Related
This question already has answers here:
Can't Overload operator<< as member function
(3 answers)
Closed 8 months ago.
From c++ how to program 10th edition by deitel
//Fig. 10.3: PhoneNumber.h
//PhoneNumber class definition
#ifndef PHONENUMBER_H
#define PHONENUMBER_H
#include <iostream>
#include <string>
class PhoneNumber
{
friend std::ostream& operator<<(std::ostream&, const PhoneNumber&);
friend std::istream& operator>>(std::istream&, PhoneNumber&);
private:
std::string areaCode; //3-digit area code
std::string exchange; //3-digit exchange
std::string line; //4-digit line
};
#endif // PHONENUMBER_H
//Fig. 10.4: PhoneNumber.cpp
//Overloaded stream insertion and stream extraction operators
#include <iomanip>
#include "PhoneNumber.h"
using namespace std;
//overloaded stream insertion operator; cannot be a member function
//if we would like to invoke it with cout << somePhoneNumber;
ostream& operator<<(ostream& output, const PhoneNumber& number)
{
output << "Area code: " << number.areaCode << "\nExchange: "
<< number.exchange << "\nLine: " << number.line << "\n"
<< "(" << number.areaCode << ") " << number.exchange << "-"
<< number.line << "\n";
return output; //enables cout << a << b << c;
}
//overloaded stream extraction operator; cannot be a member function
//if we would like to invoke it with cin >> somePhoneNumber;
istream& operator>>(istream& input, PhoneNumber& number)
{
input.ignore(); //skip (
input >> setw(3) >> number.areaCode; //input area code
input.ignore(2); //skip ) and space
input >> setw(3) >> number.exchange; //input exchange
input.ignore(); //skip dash (-)
input >> setw(4) >> number.line; //input line
return input; //enables cin >> a >> b >> c
}
//Fig. 10.5: fig10_5.cpp
//Demonstrating Class PhoneNumber's overloaded stream insertion
//and stream extraction operators.
#include <iostream>
#include "PhoneNumber.h"
#include <string>
using namespace std;
int main()
{
PhoneNumber phone; //create object phone
cout << "Enter phone number in the form (555) 555-5555:" << endl;
//cin >> phone invokes operator>> by implicitly issuing
//the non-member function call operator>>(cin, phone)
cin >> phone;
//cout << phone invokes operator<< bby implicitly issuing
//the non-member function call operator<<(cout, phone)
cout << phone << endl;
}
I understand from the book that the overloaded operator function for binary operator can be member function only when the left operand is an object of the class in which the function is a member because the member function can only be accessed by left operand which is the object of the class.
however I don't understand this part
" The overloaded stream insertion operator (<<) is used in an expression in which the
left operand has type ostream&, as in cout << classObject. To use the operator in this
manner where the right operand is an object of a user-defined class, it must be overloaded
as a non-member function. To be a member function, operator << would have to be a
member of class ostream. This is not possible for user-defined classes, since we are not
allowed to modify C++ Standard Library classes. "
my question is
whether the stream extraction and insertion operator is part of the ostream and istream respectively?
what does the part highlighted in bold mean?
My guess is that we cannot add user defined function into the C++ Standard Library class but the part in bold makes me kind of confused. do we have to add the operator << as member of class ostream to make the overloaded operator function as member function of ostream?
I always thought that stream << and >> operator were part of ostream and istream respectively.
Correct me if I am wrong. thank you in advance.
No, not for regular user defined types. The functions you made into friends in your class definition are free functions:
std::ostream& operator<<(std::ostream&, const PhoneNumber&);
std::istream& operator>>(std::istream&, PhoneNumber&);
std::basic_ostream does have some operator<< member overloads for fundamental types, such as int, and some types defined in the standard library though. If you inherit from some of those standard types, like std::basic_streambuf<CharT, Traits>, you will be able to use the basic_ostream::operator<< member overloads for those types.
It means that you are not allowed to modify the definition of std::basic_ostream to add std::basic_ostream& operator<<(const PhoneNumber&) as a member function.
You might have already read about overloading. There is not one function called operator<<, there are multiple. Some of those are class members, others aren't. The compiler will choose the right operator<< based on the two arguments.
When the compiler looks for overloads of operator<<, it will check class methods of the object on the left-hand side only. (If that's even a class. In 1<<3==8 the arguments are ints). For that reason, when the compiler sees std::cout << YourClass{} it won't look for YourClass::operator<<(ostream&).
If you wrote YourClass{} << std::cout (VERY unusual), the compiler would look in YourClass. Rules are rules, and there is no hard rule that forbids that order. But it would break the usual chaining of std::cout << a << b << c, so it's very inconvenient. So to make the usual chaining work, we do it as your textbook tells you.
Hello im having problems reading lines (ignore space characters) in an overloaded Extraction operator
this is my code any assistance would be great
istream& operator>>(istream& is, CreditAccount& Cred){
cout << "Name: ";
is.getline(Cred.name, 256);
}
my error is as follows
error: no matching function for call to ‘std::basic_istream<char, std::char_traits<char> >::getline(std::string&, int)’
we need to know the the type of Cred::name, however from your error it appears to be a std::string. the correct function to use is:
#include <string> //for std::getline
istream& operator>>(istream& is, CreditAccount& Cred){
std::cout << "Name: ";
std::getline(is, Cred.name);
return is;
}
I would also stress, that if you are using std::cout to prompt the user for input you are not using the stream extraction operator properly, it is for basic serialisation and de serialisation of an objects state. Not for user interaction. I personally would just have a "produce_credit_account()" function or the like.
EDIT: to clear std::cin
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
I have a class template, which is -- among other things -- supposed to overload istream so it accepts the user's input and adds (pushes) it into a vector, which holds type T elements.
friend istream &operator>> (istream &in, Set<T> &s)
{
int ctr = 0;
string tmp;
T val;
while (true) {
cout << "\tElement #" << ctr + 1 << ": ";
getline (in, tmp);
if (tmp == "\0") break;
// MISSING CODE HERE: "Convert" tmp into val
s.add(val);
ctr = s.size();
}
return in;
}
This works fine with Set<string>, but I need to find a way to make it function with any primitive data type, too, i.e. Set<integer>, for example.
I tried doing
stringstream(tmp) >> val
but that then doesn't work with Set<string>.
I guess the input needs to be read in as string; how, then, do I cast the input string into T type to pass it to the .add() function?
You could use a stringstream object (created from tmp) to extract the correct value if it is not a string. Note you will have to overwrite operator>> for ostream if you need more than just the built-in types (e.g. int)
Alternatively, you can define overloads of a convert() function for each T you encounter to provide proper conversion from the string tmp to the required type. The proper overload (if exists) will be selected based on your template parameter.
You can use boost::lexical_cast to convert strings to other types lexicographically.
template<class T>
friend istream &operator>> (istream &in, Set<T> &s) {
int ctr = 0;
string tmp;
T val;
while (true) {
cout << "\tElement #" << ctr + 1 << ": ";
getline (in, tmp);
if (tmp == "\0") break;
val = boost::lexical_cast<T>(tmp);
s.add(val);
ctr = s.size();
}
return in;
}
Alternatively, you can use std::istringstream.
std::istringstream sstream(tmp);
sstream >> val;
Note that boost::lexical_cast throws an exception if the cast wasn't successful, and std::istringstream does not (you need to check this manually).
There a few issues in the code that you may like to address:
getline (in, tmp);
That need to check the return value:
if(!getline (in, tmp))
// handle end-of-file or read failure
// read okay, tmp contains the read line
Next:
if (tmp == "\0") break;
It's not very common to have embedded zeros in text files. May be this piece is trying to detect the end-of-file condition, which should be handled by checking the return value of getline or if(in) statement.
stringstream(tmp) >> val;
That creates a temporary string stream and tries to invoke operator>> on it. Well, there are two kinds of operator>> for std::istream:
std::istream member functions that accept temporary (r-values) and l-values std::istream object
free standing ones that take std::istream by reference to non-const, which don't accept r-values. (In C++11 it can accept it also as std::istream&& allowing for r-values).
Hence, the above statement can only stream into built-in types for which there is a member operator>> in std::istream.
So, that statement can be replaced with:
std::istringstream ss(tmp);
ss >> val;
That would need to have error handling again to check whether entire str was parsed into val, so, as others have said here, it's easier to use boost::lexical_cast<> that does error checking for you:
val = boost::lexical_cast<T>(tmp);
If you don't insist on reading the full line, rather reading white-space separated tokens, then the loop can look like this:
template<class T>
friend std::istream &operator>>(std::istream &in, Set<T> &s) {
int ctr;
T val;
while(in >> val) {
ctr = s.size();
std::cout << "\tElement #" << ctr + 1 << ": ";
s.add(val);
}
// end-of-file or parsing failure
if(!in.eof()) {
// handle failuer to parse or read error
}
}
this is part of a homework assignment. I don't want an answer just help. I have to make a class called MyInt that can store any sized positive integer. I can only use cstring cctype iomanip and iostream libraries. I really don't understand even where to begin on this.
6) Create an overload of the extraction operator >> for reading integers from an input stream. This operator should ignore any leading white space before the number, then read consecutive digits until a non-digit is encountered (this is the same way that >> for a normal int works, so we want to make ours work the same way). This operator should only extract and store the digits in the object. The "first non-digit" encountered after the number may be part of the next input, so should not be extracted. You may assume that the first non-whitespace character in the input will be a digit. i.e. you do not have to error check for entry of an inappropriate type (like a letter) when you have asked for a number.
Example: Suppose the following code is executed, and the input typed is " 12345 7894H".
MyInt x, y;
char ch;
cin >> x >> y >> ch;
The value of x should now be 12345, the value of y should be 7894 and the value of ch should be 'H'.
The last state of my code is as follows:
istream& operator>>(istream& s, MyInt& N){
N.Resize(5);
N.currentSize=1;
char c;
int i = 0;
s >> c;
N.DigitArray[i++] = C2I(c);
N.currentSize++;
c = s.peek();
while(C2I(c) != -1){
s >> c;
if(N.currentSize >= N.maxSize)
N.Resize(N.maxSize + 5);
N.DigitArray[i] = C2I(c);
i++;
N.currentSize++;
}
}
It almost works! Now it grabs the right number but it doesn't end when I hit enter, I have to enter a letter for it to end.
You can create an operator>> overload for your class this way (as a free function, not inside the class):
std::istream& operator>>(std::istream& lhs, MyInt& rhs) {
// read from lhs into rhs
// then return lhs to allow chaining
return lhs;
}
You can use the members peek and read of istream to read in characters, and isspace to test if a character is a space, and isdigit to check if a character is a number (isspace and isdigit are in the <cctype> header).
First of all, your operator>> should be concerned only with extracting the sequence of chars from the stream and knowing when to stop based on your rules for that. Then, it should defer to a constructor of myInt to actually ingest that string. After all, that class will probably want to expose constructors like:
myInt bigone ("123456123451234123121");
for more general-purpose use, right? And, functions should have a single responsibility.
So your general form will be:
istream& operator>> (istream& is, myInt x)
{
string s = extract_digits_from_stream(is);
x = myInt(s);
return is; // chaining
}
Now how do you extract just digits from a stream and stop at a non-digit? Well, the peek function comes to mind, as does unget. I'd look at source code for the extraction operator for regular integers and see what it does.
I have the following block of code trying to overload the >> operator:
istream &operator >> (istream &stream, const Currency &obj){
cout << "Dollars: ";
stream>>obj.dollars;
cout<< "Cents: ";
stream>> obj.cents;
return stream;
}
But when I call cin>>newMoney from my main program it keeps repeating "DOLLARS:" over and over again in an endless loop like below:
Any ideas why?
I bet you have a Currency constructor that takes an 'int'. So stream>>obj.dollars; is the same as stream>>Currency(obj.dollars);. The function you pasted outputs "Dollars: " and then calls itself, outputting "Dollars: " again and then repeating forever.
I'd suggest making the constructor explicit so it doesn't misfire on you.
There is no enough information in your code (as of now). Till you post more code, all I can say is this, which is also important for you to note down: since you overload >> to take input, the object obj should be passed by non-const reference, so remove const from the second parameter, and make it look like this:
istream &operator >> (istream &stream, Currency &obj)