Why Isn't Operator Overloading for Pointers Allowed to Work

Why isn't operator overloading for pointers allowed to work?

Because if it was allowed, then it would not look good, and wouldn't be as intuitive as its with reference.

Suppose it is allowed, then you would write:

struct A{};
A a, *pa, b;

a = pa ;//doesn't look good, also not intuitive. (not real C++)

It doesn't look good, because on left side you've non-pointer, on right side you've pointer. Looks very very weird. Also, since the types don't match, it doesn't look very intuitive as to what exactly its doing. I mean, you're assigning pointer to a non-pointer; what such an assignment is supposed to do? Copying the content of the address pointed to by pointer to the destination (non-pointer) is not very inttuitive.

On the other hand, as its allowed with reference (the reality, not a supposition):

a = b; //looks good, intuitive, as now both side is same type

With reference, you've both side same type, its only when b gets passed to operator=() as argument, it is passed by reference (or say by pointer, as references are syntactic sugar of pointers.) to avoid unnecessary copy, which in turn doesn't hinder performance, as it would if it is passed by value.

It would be also interesting to note that not only b is passed by reference (or pointer underneath), a also gets passed to the function by pointer, because we know in the function, the keyword this is actually a pointer.

So references were introduced in C++, to make whole thing look good and intuitive for programmers, otherwise they're pointers underneath. In fact, most compilers implement references using pointers (pointer-mechanism) internally.

Operator overloading : cannot add two pointers

As you've discovered, trying to use arithmetic operators on pointers will result in the compiler trying to do pointer arithmetic. To call your own overloaded operator on a pointer, you can either do

Fraction *f, *g; // allocated with new
f->operator+(*g); /// Urgh!

or, almost as ugly

Fraction *f, *g;
(*f) + (*g);

One easy way to make this a bit nicer is to declare three new reference variables like this:

Fraction& f1 = *pfr1;
Fraction& f2 = *pfr2;
Fraction& f3 = *ptr3;

Where the pfrNs are the pointers to your fractions. Now if you use the reference variables, your overloaded operators will be called correctly, and you don't need to put in all the extra asterisks. The references will disappear at the end of the scope, and probably won't use any extra memory in your programme. You still need to delete the original pointers though!

C++ operator overloading for pointers

True, the rvalue reference solution is even better, as that allows stack-based objects, while this overloading would force all Vector2d objects to live on the heap, but still, it seems to be something that would have been easy to implement in compilers, possibly years before rvalue refs came around. And with custom allocators, it wouldn't even be that slow.

So is this only illegal because of the "least surprise" principle, or are there other reasons too?

  • It doesn't chain properly... what's a + b + c supposed to do, leak memory?
  • Pointer arithmetic already has a meaning in C++... it's useful for that to be consistent across types, otherwise e.g. algorithms wouldn't work properly on containers of your objects.
  • Returning something by value implies that object doesn't need clean up by the caller: if it uses free store (heap) to store actual data, it'll be deleting it automatically as necessary. Makes consistently robust memory usage easier.

Note how 'a + b' creates a new Vector object, but then copies only its address into 'c', without calling a copy constructor. So it would sort of solve the same problem that the new rvalue references solve.

The commonly implemented Return Value Optimisation also addressed this problem, helping the compiler arrange for construction of the return value directly into the caller's buffer.

Why is my operator overload not called for when I use pointers?

Your operator< is a member function, which means that it works for types Fruit, const Fruit*, and you try to pass it Fruit*, Fruit*.

When you declare an operator as a member function then the left parameter is implied to be Fruit. If you want something else, then you have to make a global operator. Unfortunately, you need a class or enumerated type as a parameter, so you can't have two pointers.

One way to get around this limitation. Instead of

cout << (fruit1 < fruit);

use

cout << (*fruit1 < fruit);

I also want you to know that this:

(fruit == fruit1)

compares the pointers not what they point to. In your case those are two distinct objects, so that pointer comparison will always return false.

Operator Overloading for struct pointers

To complete the other answers, here is the part of the C++ standard that explicitly prohibits operator overloading with two pointers (emphasis mine):

An operator function shall either be a non-static member function or
be a non-member function that has at least one parameter whose type is
a class, a reference to a class, an enumeration, or a reference to an
enumeration.
It is not possible to change the precedence, grouping, or
number of operands of operators. The meaning of the operators
= , (unary) & , and , (comma), predefined for each type, can be changed for specific class and enumeration types by defining operator
functions that implement these operators. Operator functions are
inherited in the same manner as other base class functions.

[over.oper]/6

That explains why you can't use an overloaded operator== without changing the code in your main function.

C++ Overload operator to work with vector of pointers

Overload resolution is done using the declarations visible to the compiler at the point of call. You'll need to move your operator<< overload, or at least a declaration of it, above the code using it.

And behold, it works: http://ideone.com/1BeACP

Overloading operators using pointers or objects

As you described in the comments, your Complex class is basically a variable-length string, and contains a char* plus an int.

The first thing to do, then, is to discourage the users of this class from doing new Complex, because it is not efficient. You are doing dynamic memory allocation within your class, so there is no need to do it outside as well (you're just adding more pointer indirection).

You should write your operators in the conventional way, which is to accept references, not pointers. And users will typically not need to deal with pointers, because your class abstracts the dynamic memory as an implementation detail.

For example:

class Complex
{
public:
// TODO: define constructors and assignment operator

Complex sampleFunc(Complex&); // could also return Complex& (*this)
Complex operator+(const Complex&) const;

private:
std::unique_ptr<char[]> _data;
size_t _size;
};


Related Topics



Leave a reply



Submit