Академический Документы
Профессиональный Документы
Культура Документы
compiles
links
runs
does something different than you expect
Example:
if (-0.5 <= x <= 0.5) return 0;
Pitfall:
if (-0.5 <= x <= 0.5) return 0;
Instead, it first computes -0.5 <= x, which is 0 or 1, and then compares the result with 0.5.
Moral: Even though C++ now has a bool type, Booleans are still freely convertible to int.
Since bool->int is allowed as a conversion, the compiler cannot check the validity of expressions.
In contrast, the Java compiler would flag this statement as an error.
Overloading pitfalls
Example:
class Complex
{
public:
Complex(double = 0, double = 0);
Complex operator+(Complex b) const;
Complex operator-(Complex b) const;
Complex operator*(Complex b) const;
Complex operator/(Complex b) const;
Complex operator^(Complex b) const;
// ...
private:
double _re, _im;
};
int main()
{ Complex i(0, 1);
cout << i^2 + 1; // i*i is -1
return 0;
}
Pitfall:
cout << i^2 + 1;
Using the C/C++ operator precedence rules, we can add parentheses:
cout << (i ^ (2 + 1));
Moral: You cannot change the operator precedence when overloading operators. Do not overload
an operator if its precedence is not intuitive for the problem domain.
The precedence of ^ is fine for XOR but not for raising to a power.
//: C12:TypeConversionAmbiguity.cpp
class Orange; // Class declaration
class Apple {
public:
operator Orange() const; // Convert Apple to Orange
};
class Orange {
public:
Orange(Apple); // Convert Apple to Orange
};
void f(Orange) {}
int main() {
Apple a;
//! f(a); // Error: ambiguous conversion
} ///:~
The obvious solution to this problem is not to do it. Just provide a single path for automatic conversion from one type to
another.
A more difficult problem to spot occurs when you provide automatic conversion to more than one type. This is sometimes
called fan-out:
//: C12:TypeConversionFanout.cpp
class Orange {};
class Pear {};
class Apple {
public:
operator Orange() const;
operator Pear() const;
};
// Overloaded eat():
void eat(Orange);
void eat(Pear);
int main() {
Apple c;
//! eat(c);
// Error: Apple -> Orange or Apple -> Pear ???
} ///:~
Class Apple has automatic conversions to both Orange and Pear. The insidious thing about this is that there’s no problem
until someone innocently comes along and creates two overloaded versions of eat( ). (With only one version, the code
in main( ) works fine.)
Again, the solution – and the general watchword with automatic type conversion – is to provide only a single automatic
conversion from one type to another. You can have conversions to other types; they just shouldn’t be automatic. You can create
explicit function calls with names like makeA( ) and makeB( ).