Mind Ramblings My Blog

Special semantics for arrow`->` operator and dot`.` operator in C++

Ever tried to overload operator->? If you haven’t, let me tell you this doesn’t work like other overloaded operators.

For example let us take an operator like operator*. What do you expect this to return? Lets say we have a pointer to class A, ptr_a. The operator* is already overloaded in class A. What would (*ptr_a).foo(); return?

By simple logic, *ptr_a will return the reference to the object ptr_a points to(say obj_a). And as expected the statement will execute as (obj_a).foo().

However, this logic doesn’t apply to the operator->(). As quoted from stack overflow,

The operator-> has special semantics in the language in that, when overloaded, it reapplies itself to the result. While the rest of the operators are applied only once, operator-> will be applied by the compiler as many times as needed to get to a raw pointer and once more to access the memory referred by that pointer.
struct A { void foo(); };
struct B { A* operator->(); };
struct C { B operator->(); };
struct D { C operator->(); };
int main() {
D d;
d->foo();
}
In the previous example, in the expression d->foo() the compiler will take the object d and apply operator-> to it, which yields an object of type C, it will then reapply the operator to get an instance of B, reapply and get to A*, after which it will dereference the object and get to the pointed data.
d->foo();
// expands to:
// (*d.operator->().operator->().operator->()).foo();
//   D            C            B           A*

And guess what? You can’t overload operator.(). I would like to quote Bjarne Stroustrup here from The Design and Evolution of C++, page 242, section 11.5.2 Smart References.

When I decided to allow overloading of operator ->, I naturally considered whether operator . could be similarly overloaded.

At the time, I considered the following arguments conclusive: If obj is a class object then obj.m has a meaning for every member m of that object’s class. We try not to make the language mutable by redefining built-in operations (though that rule is violated for = out of dire need, and for unary &).

If we allowed overloading of . for a class X, we would be unable to access members of X by normal means; we would have to use a pointer and ->, but -> and & might also have been re-defined. I wanted an extensible language, not a mutable one.

These arguments are weighty, but not conclusive. In particular, in 1990 Jim Adcock proposed to allow overloading of operator . exactly the way operator -> is.



comments powered by Disqus