istream extraction values with formatted string - c++

I have this formatted string in an istream.
(5, -4)
Let say :
open parenthesis
an integer number
comma and space
another integer number
close parenthesis
I would like to know what is the best approach to extract both integers and validate the string formatting.
This is in a class like this :
class MyPoint
{
public:
MyPoint() = default;
~MyPoint() = default;
...
friend ostream & operator>>(ostream & lhs, MyPoint const & rhs);
...
private:
int x, y;
};
ostream & operator>>(ostream & lhs, MyPoint const & rhs) {
// ???
}
Many thanks to all.
Here is my header file
#ifndef MYPOINT_H
#define MYPOINT_H
#include <iostream>
using namespace std;
class MyPoint
{
public:
MyPoint() : mX{ 0 }, mY{ 0 } { ; }
MyPoint(int x, int y) : mX{ x }, mY{ y } { ; }
~MyPoint() = default;
int x() const { return mX; }
int y() const { return mY; }
void setX(int x) { mX = x; }
void setY(int y) { mY = y; }
MyPoint operator-() const { return MyPoint(-mX, mY); }
MyPoint operator+(MyPoint rhs) const { rhs.mX += mX; rhs.mY += mY; return rhs; }
MyPoint operator-(MyPoint rhs) const { rhs.mX = mX - rhs.mX; rhs.mY = mY - rhs.mY; return rhs; }
MyPoint operator*(MyPoint rhs) const { rhs.mX *= mX; rhs.mY *= mY; return rhs; }
MyPoint operator/(MyPoint rhs) const { rhs.mX = mX / rhs.mX; rhs.mY = mY / rhs.mY; return rhs; }
MyPoint operator%(MyPoint rhs) const { rhs.mX = mX % rhs.mX; rhs.mY = mY % rhs.mY; return rhs; }
friend MyPoint operator+(int lhs, MyPoint const & rhs);
friend MyPoint operator-(int lhs, MyPoint const & rhs);
friend MyPoint operator*(int lhs, MyPoint const & rhs);
friend MyPoint operator/(int lhs, MyPoint const & rhs);
friend MyPoint operator%(int lhs, MyPoint const & rhs);
friend ostream & operator<<(ostream & lhs, MyPoint const & rhs);
friend istream & operator>>(istream & lhs, MyPoint & rhs);
private:
int mX, mY;
};
#endif //MYPOINT_H
And here my source file
#include "MyPoint.h"
MyPoint operator+(int lhs, MyPoint const & rhs) {
return MyPoint(lhs + rhs.mX, lhs + rhs.mY);
}
MyPoint operator-(int lhs, MyPoint const & rhs) {
return MyPoint(lhs - rhs.mX, lhs - rhs.mY);
}
MyPoint operator*(int lhs, MyPoint const & rhs) {
return MyPoint(lhs * rhs.mX, lhs * rhs.mY);
}
MyPoint operator/(int lhs, MyPoint const & rhs) {
return MyPoint(lhs / rhs.mX, lhs / rhs.mY);
}
MyPoint operator%(int lhs, MyPoint const & rhs) {
return MyPoint(lhs % rhs.mX, lhs % rhs.mY);
}
ostream & operator<<(ostream & lhs, MyPoint const & rhs) {
return lhs << "(" << rhs.mX << "," << rhs.mY << ")";
}
istream & operator >> (istream & lhs, MyPoint & rhs) {
return lhs >> "(" >> rhs.mX >> "," >> rhs.mY >> ")"; // HERE is the compiling error
}
And finally, the tests in the main
MyPoint p1, p2(2, -2);
cout << p1 << endl;
cout << p2 << endl;
With this file, I got this error :
Error C2679 binary '>>': no operator found which takes a right-hand operand of type 'const char [2]' (or there is no acceptable conversion)

For situations like this, I've often found it handy to define an overload of operator>> to read a predefined string from a stream:
std::istream &operator>>(std::istream &is, char const *pat) {
char ch;
while (isspace(static_cast<unsigned char>(is.peek())))
is.get(ch);
while (*pat && is && *pat == is.peek() && is.get(ch)) {
++pat;
}
// if we didn't reach the end of the pattern, matching failed (mismatch, premature EOF, etc.)
if (*pat) {
is.setstate(std::ios::failbit);
}
return is;
}
With this, reading your format might look something like this:
istream & operator>>(istream & lhs, MyPoint & rhs) {
return lhs >> "(" >> rhs.x >> "," >> rhs.y >> ")";
}
This will do like most typical overloads and set the stream's fail bit if the pattern you've given isn't matched. As it stands now, each string in the input can be preceded by arbitrary white space (just like conversions for numbers and such).
There is technically a minor bug here: as it stands right now, this uses the global locale's definition of whitespace. To be really correct, it should probably use the definition provided in the locale associated with the input stream.
Also note that I had to change your definition of operator>> bit; in the question it looks like an overload of operator<<, with just those two characters changed to get operator>> instead.
For a quick example:
#include <iostream>
std::istream &operator>>(std::istream &is, char const *pat) {
// implementation above
}
class Point {
int x, y;
friend std::istream &operator>>(std::istream &is, Point &p) {
return is >> "(" >> p.x >>"," >> p.y >> ")";
}
friend std::ostream &operator<<(std::ostream &os, Point const &p) {
return os << "(" << p.x <<", " << p.y << ")";
}
};
int main() {
Point p;
std::cout << "Please enter a point: ";
std::cin >> p;
std::cout << "Thanks. Point: " << p << '\n';
}
Tested with VC++ 2013, VC++ 2015, and g++ 6.1 (but this isn't pushing the limits of compilers at all, so I'd expect it to work fine even with compilers so old they're horribly broken in general (e.g., gcc 2.x or VC++ 6.0).

Related

Why does my C++ iostream overload failed when called in more complex cin and cout?

Having trouble with the overloaded IOstream in my C++ class, the code below is my header file, so there is no main(). The overloaded iostream seems to work with simple cin and cout calls, but when put into more complex ones, it throws no match for operato<< and operator>>.
/*
Provide three constructors Complex(a, b), Complex(a), and Complex(). Complex()
creates a Complex object for number 0 and Complex(a) creates a Complex object with 0 for b.
Also provide the getRealPart() and getImaginaryPart() functions for returning
the real and imaginary part of the complex number, respectively.
*/
/*
Overload the operators +, -, *, /, +=, -=, *=, /=, [ ], unary + and -, prefix ++ and --,
postfix ++ and --, <<, >>. Overload the operators +, -, *, / as nonmember functions.
*/
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
using namespace std;
class Complex{
public:
Complex();
Complex(double a);
Complex(double a, double b);
void set_I(double input);
void set_R(double input);
double get_I_comp() const; //I accessor
double get_R_comp() const; // double accessor
double getRealPart();
double getImaginaryPart();
Complex operator+(Complex other);
Complex operator+(double other);
Complex operator-(Complex other);
Complex operator-(double other);
Complex operator*(Complex other);
Complex operator*(double other);
Complex operator/(Complex other);
Complex operator/(double other);
void operator++();
Complex& operator++(int dummy);
void operator+=(Complex other);
void operator+=(double other);
void operator-=(Complex other);
void operator-=(double other);
void operator*=(double other);
void operator*=(const Complex& other);
void operator/=(double other);
void operator/=(const Complex& other);
void operator- ();
void operator+ ();
double& operator[](int index);
Complex& operator<<(const int& intput);
Complex& operator>>(const string& output);
friend ostream& operator<<(ostream& out, Complex& target);
friend istream& operator>>(const istream& input, Complex& target);
std::string toString() //temporary solution right now
{
if (this->c_I != 0){
string ret = std::to_string(c_R);
ret = ret + " + ";
ret = ret + std::to_string(c_I);
ret = ret + " i \n";
return ret;
}
else{
string ret = std::to_string(c_R);
return ret;
}
}
Complex& add(double num);
Complex& add(Complex other);
Complex& subtract(double num);
Complex& subtract(Complex other);
Complex& multiply(double num);
Complex& multiply(Complex other);
Complex& divide(double num);
Complex& divide(Complex other);
Complex& abs();
private:
double c_I;
double c_R;
};
Complex::Complex() : c_I(0),c_R(0){ //works
}
Complex::Complex(double a) :c_I(0),c_R(a){ //works
}
Complex::Complex(double a, double b){ //works // at first I have the i as a and r as b, so thats why is fliped
this->c_I = b;
this->c_R = a;
}
double Complex::get_I_comp() const{
return c_I;
}
double Complex::get_R_comp() const{
return c_R;
}
double Complex::getImaginaryPart(){
return c_I;
}
double Complex::getRealPart(){
return c_R;
}
void Complex::set_I(double input){
c_I = input;
}
void Complex::set_R(double input){
c_R = input;
}
Complex Complex::operator+(Complex other){
Complex ret( (this->c_R + other.get_R_comp() ),(this->c_I + other.get_I_comp()));
return (ret);
}
Complex Complex::operator+(double other){
Complex ret(this->c_R + other,this->c_I);
return ret;
}
Complex Complex::operator-(Complex other){
Complex ret(this->c_R - other.get_R_comp(),this->c_I - other.get_I_comp());
return ret;
}
Complex Complex::operator-(double other){
Complex ret(this->c_R - other,this->c_I);
return ret;
}
Complex Complex::operator*(double other){
Complex ret(this->c_R * other ,this->c_I *other);
return ret;
}
Complex Complex::operator*(Complex other){
if((other.get_I_comp() != 0) && (other.get_R_comp() != 0) ){
Complex ret = other * (this->c_R);
Complex neu(-(other.get_I_comp()*this->c_I),other.get_R_comp()*this->c_I);
return (ret + neu);
}
if((other.get_I_comp() == 0 ) && (other.get_R_comp() != 0)){
Complex ret(this->c_R,this->c_I);
ret = ret * other.get_R_comp();
return ret;
}
else{
Complex ret((-((this->c_I)*other.get_I_comp())),(this->c_R)*other.get_I_comp());
return ret;
}
}
Complex Complex::operator/(double other){
if (other == 0) { // zero division error handler
throw runtime_error("Math error: Can't div by zero\n");
return 1;
}
if(other != 0){
Complex ret(this->c_R/other,this->c_I/other);
return ret;
}
}
//To divide a+bi by c+id we will perform the operation (ac+bd)/(c^2 + d^2) + (bc-ad)/(c^2 + d^2)i.
Complex Complex::operator/(Complex other){
if ((other.get_I_comp() != 0) && (other.get_R_comp() != 0)){
double first = ((this->c_R)*other.get_R_comp() + (this->c_I)*other.get_I_comp())/(other.get_R_comp()*other.get_R_comp() + other.get_R_comp()*other.get_R_comp());
double second = (this->c_I*other.get_R_comp() + c_R*other.get_I_comp())/(other.get_R_comp()*other.get_R_comp() + other.get_I_comp()*other.get_I_comp());
Complex ret(first,second);
return ret;
}
if((other.get_I_comp() == 0 ) && (other.get_R_comp() != 0)){
Complex ret(this->c_R,this->c_I);
ret = ret *(1/other.get_R_comp());
return ret;
}
else{
Complex ret(this->c_R,this->c_I);
Complex neu(1/other.get_I_comp());
ret = ret * neu;
return ret;
}
}
void Complex::operator++(){
c_R++;
}
Complex& Complex::operator++(int dummy){
Complex temp = *this;
++temp;
c_R++;
return temp;
}
void Complex::operator+=(double other){
c_R += other;
}
void Complex::operator+=(Complex other){
c_R += other.get_R_comp();
c_I += other.get_I_comp();
}
void Complex::operator-=(double other){
c_R +=(-1*other);
}
void Complex::operator-=(Complex other){
c_R -= other.get_R_comp();
c_I -= other.get_I_comp();
}
void Complex::operator*=(double other){
Complex& reference = *this; //pass by reference editing
reference = reference* other;
}
void Complex::operator*=(const Complex& rhs){
Complex& reference = *this;
reference = reference * rhs;
}
void Complex::operator/=(double other){
Complex& reference = *this;
reference = reference / other;
}
void Complex::operator/=(const Complex& rhs){
Complex& reference = *this;
reference = reference / rhs;
}
double& Complex::operator[](int index){
if(index <= 1){
return(index == 0 ? c_R : c_I);
}
else{
throw std::out_of_range ("index outta bound");
}
}
void Complex::operator-(){
c_R*=(-1);
c_I*=(-1);
}
void Complex::operator+(){
if(c_R<0){
c_R*=(-1);
}
if(c_I<0){
c_I*=(-1);
}
}
Complex& Complex::add(double num){
Complex& reference = *this;
reference = reference + num;
return reference;
}
Complex& Complex::add(Complex other){
Complex& reference = *this;
reference = reference + other;
return reference;
}
Complex& Complex::subtract(double num){
Complex& reference = *this;
reference = reference - num;
return reference;
}
Complex& Complex::subtract(Complex other){
Complex& reference = *this;
reference = reference - other;
return reference;
}
Complex& Complex::multiply(double num){
Complex& reference = *this;
reference = reference*num;
return reference;
}
Complex& Complex::multiply(Complex other){
Complex& reference = *this;
reference = reference * other;
return reference;
}
Complex& Complex::divide(double num){
Complex& reference = *this;
reference = reference/num;
return reference;
}
Complex& Complex::divide(Complex other){
Complex& reference = *this;
reference = reference/other;
return reference;
}
Complex& Complex::abs(){
Complex& reference = *this;
+reference;
return reference;
}
ostream& operator<<(ostream& out, Complex& target){
out << "Real : ";
out << " " << target.getRealPart();
out << " imaginary :";
out <<target.getImaginaryPart();
return out;
}
istream& operator>>(const istream& input, Complex& target) {
string use;
input>>use;
stringstream convert(use);
int x = 0;
convert>>x;
target.set_R(x);
return input;
}
when doing calls such as
cout << "(" << number1 << ")" << " + " << "(" << number2 << ") = " << (number1 + number2) << endl;
it throws the following exception:
main.cpp:19:69: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream’ and ‘Complex’)
cout << "(" << number1 << ")" << " + " << "(" << number2 << ") = " << (number1 + number2) << endl;
In file included from main.cpp:1:0:
Complex.h:276:10: note: candidate: std::ostream& operator<<(std::ostream&, Complex&)
ostream& operator<<(ostream& out, Complex& target){
You have to overload the following function too!.
ostream& operator<<(ostream& out, Complex&& target){
out << "Real : ";
out << " " << target.getRealPart();
out << " imaginary :";
out <<target.getImaginaryPart();
return out;
}
Non-const references don't bind to temporaries.
So ostream& operator<<(ostream& out, Complex& target) can't be used in code that looks like cout << Complex{1.0} or cout << (complex1 + complex2), because in both cases the second argument is a temporary Complex instance.
A possible fix is to use const references when you don't plan to modify the argument:
ostream& operator<<(ostream& out, Complex const& target)
Another solution (for small objects) is to accept it by-value:
ostream& operator<<(ostream& out, Complex target)

c++ multiple operator overloading

I want to overload some operators multiple times and i am not sure how to do it i have a class
for example
int main(){
addClass c1;
addClass c2;
addClass c1 = (c2 + 10 * c2 + 2 * c3)*c3;
}
my problem is that i dont know how to make this many opreator ovrloading, I mean what do i need to return in ordear for it to continue to the next opreator?
I tried that
class addClass
//declration
friend addClass & operator*(const double, const addClass &);
addClass & operator*(double x, const addClass & a1)
{
int i;
addClass add(a1.rank);
add.res=x*a1.res
}
return res;
}
but for the next oprators i run into some problems so i wanted to know what to do
Thank you!
The order of evaluation is the same as usual even for overloaded operators, so with this example where I've added printing in the operators ...
#include <iostream>
class addClass {
public:
addClass() : addClass(0) {}
// converting constructor
addClass(int x) : value(x) {}
addClass& operator+=(const addClass& rhs) {
value += rhs.value;
return *this;
}
addClass& operator-=(const addClass& rhs) {
value -= rhs.value;
return *this;
}
addClass& operator*=(const addClass& rhs) {
value *= rhs.value;
return *this;
}
addClass& operator/=(const addClass& rhs) {
value /= rhs.value;
return *this;
}
int getValue() const { return value; }
private:
int value;
};
std::ostream& operator<<(std::ostream& os, const addClass& ac) {
return os << ac.getValue();
}
addClass operator+(addClass lhs, const addClass& rhs) {
std::cout << lhs << '+' << rhs << '=';
lhs += rhs;
std::cout << lhs << '\n';
return lhs;
}
addClass operator-(addClass lhs, const addClass& rhs) {
std::cout << lhs << '-' << rhs << '=';
lhs -= rhs;
std::cout << lhs << '\n';
return lhs;
}
addClass operator*(addClass lhs, const addClass& rhs) {
std::cout << lhs << '*' << rhs << '=';
lhs *= rhs;
std::cout << lhs << '\n';
return lhs;
}
addClass operator/(addClass lhs, const addClass& rhs) {
std::cout << lhs << '/' << rhs << '=';
lhs /= rhs;
std::cout << lhs << '\n';
return lhs;
}
int main(){
addClass c1;
addClass c2 = 100;
addClass c3 = 2;
c1 = (c2 + 10 * c2 / 2 * c3)*c3;
}
... you would get this output:
10*100=1000
1000/2=500
500*2=1000
100+1000=1100
1100*2=2200

C++ Member Function Cannot Change Private Field [duplicate]

This question already has an answer here:
About c++11 range for loops and iterators
(1 answer)
Closed 7 years ago.
OH! I found the problem. As I said at end, it was a simple problem.
In for loop, i iterated wiht copy of "Particle"s. I updated them but the operation does not affect the original values that stored in vector.
For requests about solution one can access the particle objects using 3 major ways.
lvalue-ref object way:
for (auto& p: particles)
...
Or by iterators:
for (auto it=particles.begin(); i<particles.end();++it)
...
Or by plain indexes:
for (size_t i=0; i<particles.size(); ++i)
...
For ones that curious about code, you may look below:
If I am not missing something very obvious, I encountered with a really strange problem.
To simplify the problem, I have a class named "Particle", which has a function called "update". Particle class has some private variables like position, velocity etc. And update function is supposed to make some calculations and add proper values to that private variables. But, that simply does not work.
Actually, I am sceptical about the type of that variables which is a class written by me, "Vector2".
To add values to variables, I've used the "+=" operator, and I think I implemented them correctly(?) in my Vector2 class.
To clarify situation, IMHO, it is better to give some code:
This is my Vector2.h :
namespace sim {
#include <ostream>
#include <cmath>
using namespace std;
struct Vector2 {
double x, y;
Vector2& operator+=(const Vector2& rhs) {
this->x += rhs.x;
this->y += rhs.y;
cout << "op+=" << endl;
return *this;
}
Vector2& operator*=(double k) {
x *= k;
y *= k;
cout << "op*=" << endl;
return *this;
}
friend ostream& operator<<(ostream& os, const Vector2& v2);
friend Vector2 operator+(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator-(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator*(Vector2 lhs, double k);
friend Vector2 operator*(double k, Vector2 rhs);
};
ostream& operator<<(ostream& os, const Vector2& v2) {
os << "[ " << v2.x << "; " << v2.y << " ]";
return os;
}
Vector2 operator+(Vector2 lhs, const Vector2& rhs) {
lhs += rhs;
cout << "op+" << endl;
return lhs;
}
Vector2 operator*(Vector2 lhs, double k) {
lhs *= k;
cout << "op*" << endl;
return lhs;
}
(removed some unrelated parts like constructor)
And this is Particle class:
class Particle {
private:
Vector2 pos;
Vector2 vel;
Vector2 acc;
double rad;
SDL_Color clr;
public:
Particle(
Vector2 _p,
Vector2 _v,
Vector2 _a,
double _r = 10.0,
SDL_Color _c = { 255, 255, 255, 255 }) {
pos = _p;
vel = _v;
acc = _a;
rad = _r;
clr = _c;
}
Vector2& move_particle(Vector2 move_by) {
return (pos += move_by);
}
void update(double dt) {
this->vel += acc * dt;
this->pos += vel * dt;
cout << "update " << pos << vel << acc << endl;
}
void render(SDL_Renderer* renderer) {
// TODO: this was supposed to be a circle, but, who cares? ;)
SDL_Rect r = { int(pos.x), int(pos.y), int(rad), int(rad) };
SDL_RenderFillRect(renderer, &r);
cout << "render" << endl;
}
};
And the result: update does not update.
How do I know (guess) my overloads DOES work?
For 3 Vector2 objects, I can do any kind of operation I defined correctly.
And the results are just what they supposed to be. (Or, maybe not?)
But debugging update function roughly brings me to the point that actually += operator works for one time, and not again BUT this behaviour is showing itself only in update function.
And I know, this will be such a simple mistake that I possibly feel ashamed (just kidding).
Oh, and the main code of course:
int main() {
SDL_Init(SDL_INIT_EVERYTHING);
auto window = SDL_CreateWindow("My Very First Particle Simulation", -1, -1,
1024, 768, SDL_WINDOW_SHOWN);
auto renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
const Vector2 g(0.0, 9.8);
double dt = 0.1;
std::vector<Particle> particles;
bool quit = false;
while (!quit) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
quit = true;
break;
case SDL_MOUSEBUTTONUP:
particles.emplace_back(Vector2(event.button.x, event.button.y), Vector2(1.0, 0.0), g);
break;
default:
break;
}
SDL_RenderClear(renderer);
for (auto p : particles) {
p.update(dt);
p.render(renderer);
}
SDL_RenderPresent(renderer);
}
}
}
Some comments on your code,
you can just change these to be member functions
friend Vector2 operator+(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator-(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator*(Vector2 lhs, double k);
friend Vector2 operator*(double k, Vector2 lhs);
as in
Vector2 operator+(const Vector2& rhs);
Vector2 operator-(const Vector2& rhs);
Vector2 operator*(const double k);
friend Vector2 operator*(const double k, Vector2 lhs);
In them copy this to a new Vector2 and then update the value and return. The fourth function is kept as friend so that you can have something like double*Vector2 while the third one takes care of Vector2*double
Any operation that has Vector2 as the left operand can be done as a member function.
I can see that these two operators are taking their first args by value. Change them so the take their args by reference.
Vector2 operator+(Vector2 lhs, const Vector2& rhs) { // lhs should be a const reference
lhs += rhs;
cout << "op+" << endl;
return lhs;
}
Vector2 operator*(Vector2 lhs, double k) { // lhs should be a const reference
lhs *= k;
cout << "op*" << endl;
return lhs;
}
EDIT:
Also these functions should take their class args as const referenecs:
friend Vector2 operator+(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator-(Vector2 lhs, const Vector2& rhs);
friend Vector2 operator*(Vector2 lhs, double k);
friend Vector2 operator*(double k, Vector2 rhs);

c++ generic operator overload

How could I use operator overloading to add two objects without making it a member of of any object? Is this something to do with insertion operator overloading?
so instead of this, to use something more generic i.e. to be used with any objects?:
sameObjectType operator + ( const sameObjectType &x, const sameObjectType &y ) {
sameObjectType z;
z = x+y;
return z;
}
// I want to do the same for subtraction operatoR
sameObjectType operator - ( const sameObjectType &x, const sameObjectType &y ) {
sameObjectType z;
z = x-y;
return z;
}
You can get the idea from this sample code.
#include <iostream>
class One {
private:
int num1, num2;
public:
One(int num1, int num2) : num1(num1), num2(num2) {}
One& operator += (const One&);
friend bool operator==(const One&, const One&);
friend std::ostream& operator<<(std::ostream&, const One&);
};
std::ostream&
operator<<(std::ostream& os, const One& rhs) {
return os << "(" << rhs.num1 << "#" << rhs.num2 << ")";
}
One& One::operator+=(const One& rhs) {
num1 += rhs.num1;
num2 += rhs.num2;
return *this;
}
One operator+(One lhs, const One &rhs)
{
return lhs+=rhs;
}
int main () {
One x(1,2), z(3,4);
std::cout << x << " + " << z << " => " << (x+z) << "\n";
}

Operator>> Overloading

I am implementing a complex number using operator overloading. In the program, the user enters a complex number ALWAYS in the form:
a + bi
So, in example...
25.0 + 3.6i
Assume that the user will always enter both the real and the imaginary parts of the complex number, e.g., the user will enter "5 + 0i" (and not "5") or "0 - 6.2i" (and not "-6.2i").
My problem is that in main() I have the following code:
ComplexNumber c1;
cin >> c1;
cout << c1;
and the code prints:
0 + 0i
...when I entered "4.2 + 8.3i" into the prompt during runtime.
Here is my implementation of my operator>> class:
istream & operator>>(istream & in, ComplexNumber & n) {
string real;
string imag;
bool done = false;
int sign = 1;
string num;
in >> num;
int length;
for (int i = 0; i < num.length(); i++) {
if (num.at(i) == 'i') {
imag = num.substr((i - length), i);
}
else if (num.at(i) == '-') {
sign = -1;
}
else if (num.at(i) == ' ') {
if (!done) {
real = num.substr(i);
done = true;
}
length = 0;
}
length++;
}
n = ComplexNumber(atof(real.c_str()), atof(imag.c_str()) * sign);
return in;
}
Here is my implementation of operator<< class:
ostream & operator<<(ostream & out, const ComplexNumber & n) {
n.print(out);
return out;
}
Here is my implementation of the ComplexNumber member class print():
void ComplexNumber::print(ostream & out) const {
if (imag >= 0)
out << real << " + " << imag << "i";
else
out << real << " - " << (-1 * imag) << "i";
}
This is my ComplexNumber header file for further details:
#ifndef COMPLEXNUMBER_H
#define COMPLEXNUMBER_H
#include <iostream>
using namespace std;
class ComplexNumber {
public:
// constructors
ComplexNumber();
ComplexNumber(double real_part, double imaginary_part);
ComplexNumber(const ComplexNumber & rhs);
// named member functions
void print(ostream & out = cout) const;
bool equals(const ComplexNumber & rhs) const;
// assignment operators
const ComplexNumber & operator=(const ComplexNumber & rhs);
const ComplexNumber & operator+=(const ComplexNumber & rhs);
const ComplexNumber & operator-=(const ComplexNumber & rhs);
const ComplexNumber & operator*=(const ComplexNumber & rhs);
private:
double real;
double imag;
};
// arithmetic operators
ComplexNumber operator+(const ComplexNumber & lhs, const ComplexNumber & rhs);
ComplexNumber operator-(const ComplexNumber & lhs, const ComplexNumber & rhs);
ComplexNumber operator*(const ComplexNumber & lhs, const ComplexNumber & rhs);
// relational operators
bool operator==(const ComplexNumber & lhs, const ComplexNumber & rhs);
bool operator!=(const ComplexNumber & lhs, const ComplexNumber & rhs);
// I/O operators
ostream & operator<<(ostream & out, const ComplexNumber & n);
istream & operator>>(istream & in, ComplexNumber & n);
#endif
Any help with my implementations would be great.
Essentially your operator >> is way too complex, and doesn’t even handle errors properly. You shouldn’t read the value into a string to begin with – read it directly into a number. Furthermore, after each read operation you need to check (and potentially set) the stream’s state.
istream& operator >>(istream& in, ComplexNumber& value) {
int re;
if (not (in >> re)) {
return in;
char pm;
if (not (in >> pm) or (pm != '+' and pm != '-') {
in.setstate(ios::failbit);
return in;
}
int im;
if (not (in >> im))
return in;
char i;
if (not (in >> i) or i != 'i') {
in.setstate(ios::failbit);
return in;
}
value = ComplexNumber {re, (pm == '-' ? -im : im)};
return in;
}
(I used C++11 initialisers because I’m lazy ….)
And, yes, this can be written even shorter by pulling the whole reading into a single chainged expression:
istream& operator >>(istream& in, ComplexNumber& value) {
int re;
int im;
char pm;
char i;
if (not (in >> re >> pm) or
(pm != '+' and pm != '-') or
not (in >> im >> i) or
i != 'i')
{
in.setstate(ios::failbit);
return in;
}
value = ComplexNumber {re, (pm == '-' ? -im : im)};
return in;
}
Whether this is better depends on the audience. Personally, I do find it more (!) readable than the first version. A more structured alternative (which would be overkill for such a simple case) is Boost.Qi which allows very elegant parser construction.
This part:
string num;
in >> num;
It reads only one word from input. You would need to call it several times to read something like 4.2 + 8.3i, which has three words.