Show Lecture.ExtensibleNotMutable as a slide show.
CS253 Extensible Not Mutable
Extensible, not mutable
- C++ is extensible, not mutable.
- extensible: you can extend the language—you can add functionality.
- mutable: you cannot change the language.
2+2
will always be 4
.
Extending
int main() {
string sin = "Impeached: ";
string litany = sin + 17 + ' ' + 42 + ' ' + 45*2; // 🦡
cout << litany << '\n';
}
c.cc:3: error: no match for ‘operator+’ in ‘sin + 17’ (operand types
are ‘std::string’ {aka ‘std::__cxx11::basic_string<char>’} and
‘int’)
That failed, because you can’t use +
on a std::string
and an int.
Extending
string operator+(const string &s, int n) {
return s + to_string(n);
}
int main() {
string sin = "Impeached: ";
string litany = sin + 17 + ' ' + 42 + ' ' + 45*2;
cout << litany << '\n';
}
Impeached: 17 42 90
Hooray! C++ is extensible! I extended the language to include
string + int
.
For all I know, there’s some obscure
(that means something I don’t know) line of the C++ standard that
forbids overloading operators with all built-in and std::
operands.
More Extending
class Fraction {
int top, bot;
public:
Fraction(int num, int den) : top(num), bot(den) { }
double get() const { return top*1.0/bot; }
};
int main() {
Fraction f(355, 113);
cout << f << '\n'; // 🦡
}
c.cc:10: error: no match for ‘operator<<’ in ‘std::cout << f’ (operand
types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and
‘Fraction’)
Of course, that failed. <<
has no idea what to do with
an ostream (output stream) and a Fraction
.
More Extending
class Fraction {
int top, bot;
public:
Fraction(int num, int den) : top(num), bot(den) { }
double get() const { return top*1.0/bot; }
};
ostream & operator<<(ostream &os, const Fraction &f) {
return os << f.get();
}
int main() {
Fraction f(355, 113);
cout << f << '\n';
}
3.14159
- Hooray! I extended the language to include
ostream << Fraction
.
- Why is
operator<<
not a method of Fraction
?
How operators work
- For an operator to be a method of
class Fraction
, it must
take a Fraction
as its left-hand argument.
- It would only take a single explicit argument—the other, implicit,
left-hand argument would be
*this
, the current object.
- In the case of
cout << f
, the left-hand argument is an ostream.
- You can’t add methods to
class ostream
.
- It’s not yours.
- That class is finished.
- Therefore, in this case,
operator<<
is not a method;
it is, instead, a free function.
Mutation
Consider this surprising result:
cout << "Friday" + 3;
day
"Friday"
is an array of const char
, or a const char *.
- Adding
3
to a pointer moves it forward three items.
I don’t like this. I want it to simply append a "3"
to the string.
Let’s redefine it!
Futility
string operator+(const char *p, int n) { // 🦡
return p + to_string(n);
}
int main() {
cout << "Friday" + 3;
}
c.cc:1: error: ‘std::string operator+(const char*, int)’ must have an
argument of class or enumerated type
- That failed; I can’t mutate the language.
const char * + int
is already defined, and I can’t change it.
More Futility
string operator%(const char *p, int n) { // 🦡
return p + to_string(n);
}
int main() {
cout << "Friday" % 3;
}
c.cc:1: error: ‘std::string operator%(const char*, int)’ must have an
argument of class or enumerated type
- Here, we’re not trying to redefine anything, since
"C-string" % 3
isn’t defined, but it still fails.
- One of the operator function arguments must be a
user-defined type.
- The message said that—we just didn’t bother to read it.
- Maybe it allows new operations to be defined in the
core language?