我正在尝试重载instream运算符>>对于分数类。我创建了一个函数,可以从用户获取一个字符串并将其解析为我的Fraction类的正确参数但我不确定如何在我的>>中实现它重载功能。
用户可以输入三种类型的分数: 整数(例如5) 2.混合数字(例如2 + 4/5) 3.常规分数(例如1/2)
我的方法是将此输入作为主函数中用户的字符串接受,解析它以获取有效的Fraction类参数,然后将此新创建的fraction对象返回到流。我只是不确定如何做到这一点。
在我的运算符重载定义中,我有:
istream& operator>>(istream& in,const Fraction& input)
但是如果我接受一个字符串,那么这里的参数类型不应该是一个字符串吗?我对这一部分感到非常困惑。我想再返回一个Fraction对象。这是处理整数的一个例子。
int num1 = atoi(input.c_str());
Fraction output(num1);
in >> output;
return in;
我在这里走在正确的轨道上吗?
答案 0 :(得分:5)
您的分数必须是输出参数,因此不能是const
:
istream& operator>>(istream& in, Fraction& input)
然后在您的函数中,您将提取到std::string
然后解析,并将相关数据存储到input
Fraction
对象中。
答案 1 :(得分:2)
以下是我为演示代码所做的工作,因为其他人已经解释了这些问题。
class Fraction {
int top, bottom;
public:
Fraction(int top_, int bottom_) :top(top_), bottom(bottom_) {}
Fraction(const Fraction& rhs) : top(rhs.top), bottom(rhs.bottom) {}
Fraction& operator=(const Fraction& rhs) {top=rhs.top; bottom=rhs.bottom; return *this}
int get_numerator() {return top;}
int get_denomerator() {return bottom;}
double get_value() {return double(top)/bottom;}
};
istream& operator>>(istream& in, Fraction& input) {
int numer;
int denom=1;
int whole=0;
int peekchar;
bool valid=false;
in >> numer; //get the numerator
peekchar = in.peek(); //peek at next character
if(in && peekchar == '+') { //if next character is a +
in.get(); //skip the + character
whole = numer; //then first character was whole, not numerator
in >> numer; //get the real numerator
valid = true;
peekchar = in.peek();
}
if(in && peekchar == '/') { //if next character is a /
in.get(); //skip the / character
in >> denom; //get the denominator
valid = true;
}
if (in || valid) { //if we succeeded in reading
if (denom == 0)
denom = 1;
numer += (whole*denom);
input = Fraction(numer, denom);
}
return in;
}
ostream& operator<<(ostream& in,const Fraction& output) {
return in << output.get_numerator() << '/' << output.get_denominator();
}
int main() {
Fraction my_fract;
cout << "Enter a fraction\n";
cin >> my_fract;
cout << "you entered " << my_fract;
}
}
答案 2 :(得分:1)
您应该使用streams
,而不是strings
。如果用户想要输入/输出string
,则可以始终使用stringstream
。请注意,您的定义是
istream& operator>>(istream& in,const Fraction& input)
以流语言表示从Fraction
中提取istream
,因此您的输入参数不应为const。另一方面,要将Fraction
输出到ostream
,将声明
ostream& operator<<(ostream& in,const Fraction& input) //Here const is good
另外,最后要注意的是istream/ostream
是使用char
作为元素和默认特征的特定实现。更通用的实现适用于任何类型的流,运算符定义如下
template< typename Elem, typename Traits >
std::basic_istream< Elem, Traits >& operator>>(std::basic_istream< Elem, Traits >& in, Fraction& input)
template< typename Elem, typename Traits >
std::basic_ostream< Elem, Traits >& operator<<(std::basic_ostream< Elem, Traits >& out, Fraction const& output)
答案 3 :(得分:1)
对于要为operator>>
类重载的Fraction
函数,而不是输入std::string
,解析它,然后尝试创建一个新Fraction
来自解析参数的对象,您应该在operator>>
重载函数内对用户输入进行所有解析,因为它已经可以直接访问输入流。换句话说,你正在做的事情是多余的,有点令人困惑......对于operator>>
对象的Fraction
重载,目的应该是获取整个用户输入并创建一个{{来自该用户输入的对象...在Fraction
对象完成之前不会经过几个步骤。
所以你会想要这样的东西:
Fraction
并使用它:
//set values of Fraction object through pass-by-reference
istream& operator>>(istream& in,Fraction& input);
最后,如果在尝试解析用户输入时发现它没有正确格式化,或者类型错误等,请通过调用{{1}来设置Fraction new_fraction_obj; //has only default-constructor-set values
std::cin >> new_fraction_obj; //now will have the user-input values after call
对象的失败位因此,流的用户可以检测到输入有问题,并且正在通过引用传递的istream
对象处于无效状态。
答案 4 :(得分:0)
标准方法是将自定义输入操作分解为成分:
std::istream & operator>>(std::istream & in, Fraction & input) // not const!
{
std::string token;
if (!(in >> token)) { return in; } // error
int num, den;
const bool res = parse_token(token, num, den); // write this!
if (!res)
{
in.setstate(std::ios::failbit);
return in;
}
input.set(num, den); // or whatever
}
关键是写parse_token(const std::string &, int &, int &)
函数来确定字符串是否代表有效分数,如果是,则将分子和分母放在两个相应的变量中。