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 pfrN
s 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
How to Handle a Ctrl-Break Signal in a Command Line Interface
C++ Delete Does Not Free All Memory (Windows)
C++ Virtual Function Table Memory Cost
Xcode 3.2.1 and C++ String Fails!
Why Does 'Std::Basic_Ifstream<Char16_T>' Not Work in C++11
How to Convert a Byte Array into Double in C
How Does the Friend Keyword (Class/Function) Break Encapsulation in C++
How to Take Ownership of an Abandoned Boost::Interprocess::Interprocess_Mutex
How to Convert a Value from Host Byte Order to Little Endian
Simple For() Loop Benchmark Takes the Same Time with Any Loop Bound
Is It Legal to Modify the Result of Std::String::Op[]
What Does Afx_Manage_State(Afxgetstaticmodulestate()) Do Exactly
Stl Container with Std::Unique_Ptr's VS Boost::Ptr_Container
Error C1083: Cannot Open Include File: 'Stdafx.H'
Why Does (I|O)Fstream Take a Const Char* Parameter for a File Name
I++ Less Efficient Than ++I, How to Show This