I've been reading up on class operators and came across the following example:
class Array {
public:
int& operator[] (unsigned i) { if (i > 99) error(); return data[i]; }
private:
int data[100];
};
Does this mean I can replace [ and ] with whatever I want? For example, could I use parentheses?
Also, what is the significance of the ampersand in int& operator[]?
On a slightly less important note, would it be syntactically correct to use int& operator [] instead of int& operator[]?
Does this mean I can replace [ and ] with whatever I want?
Nopes! Not all operators can be overloaded.
For example, could I use parentheses?
You can but you shouldn't.
Also, what is the significance of the ampersand in int& operator[]?
It means you are returning a reference to an int variable.
EDIT: On a slightly less important note, would it be syntactically correct to use int& operator [] instead of int& operator[]?
There is no difference between the two.
What you are doing is defining an Array class that wrapes a simple integer array. By overloading the [] operator you can acces each element of the array as with any other array, the advantage here is that your are checking superior limit to avoid buffer overflow. The ampersand means that you are returning a reference to the array element, it allows you both assigment a value and getting a value. In c++ when you overload the [] operator dont forget both const and non-const versions:
int& operator[] (conts int a) {...}
int operator[] (conts int a) {...} const
You could use parentheses, because there also is an
operator()
and some libraries (eg. boost::blas) do this. BUT: You cannot make up new parenthesis, because there is no operator{} or operator<>
RE your syntax question: Haven't tried, but don't think so, because operator[] is the name of a function, and you shouldn't add whitespace to a function name.
While you can mostly define operators as you like, parens would be a problem. The reason is conflict with the classes constructor! Array(25), what does it mean? I'm not sure if this is allowed (though I'm quite sure someone else will know), but the point is that even if you are allowed you are going to have a problem with doing that.
In general - symbols that serve as operators can be overloaded/redefined You can specify how ==, &, > and [] work for your class. You can't decide the letter 'q' now means some type of comparison. As far as the () issue, im not sure.
The reference mark & is necessary for indexing because you want to potentially do assignment on the address returned, not just got a value. If you permit the lax description, the "majority' of your operators will not require this.
1) NO there is a fixed set of available 'overloadable' operators in C++.
See this table in wikipedia:
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Table
There is an 'Overloadable' Column in each table
2) The int& indicates that you're returning a Reference to the value.
References in C++ are similar to pointers and worth their own discussion, but in the case of the operator here what it allows if for you to use this operator as the left hand operand of an assignment e.g.
x[3] = 0;
This wouldn't work if it just returned an int;
Related
Assuming a function needs a pointer to a vector of type T but when I have only a vector of vector of type T(type is not guaranteed to be a POD), is this
std::vector<std::vector<T>> input;
auto selectedVectorPtr=&input[j];
safer than this
std::vector<std::vector<T>> input;
auto selectedVectorPtr=&(input[j]);
also assuming input's scope doesn't end until that function which takes selectedVectorPtr as parameter.
My concerns(/misconceptions) are:
does () create any temporary object? So is taking address of it is bad?
does operator overloading of & or [] on type T have any effect on changing priority of operator precedence?
what if vector(or both) is resized after getting address?
operator[] has higher precedence then operator& (postfix operators have the highest precedence), so it is evaluated first here, no parenthesis needed. There is no difference between &input[j] and &(input[j]) here.
Alternative simpler syntax:
auto selectedVectorPtr = input.data() + j;
No need for std::addressof here either.
The operator precedence dictates that [] is evaluated before the leading &. Hence, there is no difference in the two expressions.
As you were wondering about the safety implications of the snippets, there are two issues to consider for &input[j] (regardless of the outer parentheses):
The index can be out of bounds, leading to undefined behavior. You might want to use the (possibly throwing but safer) std::vector::at instead of std::vector::operator[] and wrap that into a try-catch block.
If you want to take the address of T, which is unknown a priori, operator & could be overloaded for T. While this is evil in the first place, you can use std::addressof to mitigate the possibility. Note that this is not necessary in your case, as you're taking the address of a std::vector instance.
&input[j] and &(input[j]) will not have any difference. This is because operator[] have higher precedence then that of operator&.
So in both the cases it will evaluate to &(input[j])
In C++ one can add implicit-conversion operators in a class or struct. For instance, 3D vector types usually include something like:
struct Vector {
float x, y, z;
operator float * () { return reinterpret_cast<float *>(this); }
};
to allow accessing the vector's elements with subscripts, passing to functions that want a pointer, etc. It occurred to me to wonder: can we instead write a conversion operator that returns a reference to array of float, instead of a pointer to float?
(This is of purely academic interest. I don't know what benefits a reference-to-array would have, if any, over a simple pointer.)
As a free function we can do this like:
float (&convert(Vector & v))[3]
{
return reinterpret_cast<float(&)[3]>(v);
}
Vector v;
convert(v);
However, I haven't been able to find the right syntax to do this as a conversion operator. I've tried things like:
operator float(&)[3] ()
operator float(&())[3]
float (&operator())[3]
and various other permutations, but I just get various syntax errors (g++ 4.8.1).
Is it possible to write a conversion operator returning a reference to array, and if so, what is the syntax to do so?
In fact you can, you almost had it with the last one:
(&operator float())[3];
As for the question of whether or not a typedef is ever necessary, I think it is from reading the comments on https://stackoverflow.com/a/6755760/2925619 (which answer is what helped me get the syntax for the above as well).
Edit:
Apparently, this syntax is incorrect and returning a reference to an array is forbidden as chris discovered for us. I guess you'll just have to settle for a typedef.
If you are using C++11, the problem may be resolved by introducing the ref/ptr template aliases as defined below:
template<typename T>
using ref = T&;
template<typename T>
using ptr = T*;
With this aliases the declaration of reference to array conversion operator will be in form:
operator ref<float[3]>();
Also it make function taking/returning pointer to function/array declaration much cleaner, e.g.:
ptr<int()> foo(ptr<int(int)> bar);
Instead of:
int (*foo(int(*bar)(int)))();
Is it possible to overload operators in such a way that you can capture a specific combination of them? For example lets say I have a custom object myObject of type MyType where [] is already overloaded to pass such calls down to a map object. That said, in the case of the following code:
int value = myObject["someProp"];
I'm already overloading [] but in this case I'd like to know when [] is being called on the object in an assignment, with a reference to the type of object that the property lookup is to be assigned to. This way I can cast the value coming out of the dynamic property lookup and so on and so forth. Any input is appreciated!
For more insight into exactly what I'm trying to accomplish, see this related question of mine.
No, you can't overload on the return type, or on the context in which the call appears (e.g. in an assignment etc).
You could, however, return a proxy object that would have a bunch of overloaded conversion operators. Without seeing what you intend to do, it's hard to say how far you might be able to get with this approach, or whether it's even a sane thing to do.
If you want type deduction for things like this, your best bet is to overload operator() instead, and pass in the thing you're going to be assigning to as a dummy parameter, i.e.:
MyType myObject;
int value = myObject("someProp", value);
I've made something like this work pretty well in the past. In particular, see e.g.:
https://github.com/sgolodetz/hesperus2/blob/master/source/engine/core/hesp/objects/base/ObjectManager.tpp
In principle, it's rather straightforward to do: all that is needed is
for your operator to return a proxy which then overloads the operators
you want to catch. In practice, it can cause more than a few problems;
readers will expect (a op1 b) op2 c to have
the same semantics as T tmp(a ip1 b); tmp op2
c. There are some common exceptions, however:
The operator[] in a multi-dimensional array will often return a
proxy which defines an operator[] itself, in order to support [][]
correctly.
More generally, a container which for whatever reasons needs to know
when a value is modified will have an operator[] which returns a
proxy; within the proxy, assignment is defined as setting the value in
the owning container, and there will be a convertion operator to the
value type, for use in rvalue contexts. Of course, this means that
things like m[i][j].funct() don't work; typically, however, this sort
of thing is used for matrices of numeric types, where member functions
aren't that relevant.
In contexts where it is desirable to support overload resolution based
on the target type (your example), the function can return a proxy with
overloaded conversion operators. You want to be extremely careful with
this—overloaded conversion operators are often a recipe for
overload resolution ambiguities&rdash;but there are enough exceptions
that this situation bears mentionning. (Important, here, is that the
results of the operator will amost always be used to intialize or to
assign to a specific object, the type of which determines which
conversion operator will be called.)
BTW: I might mention that in the example you give, there is no
assignment; it is a classical initialization. In this case, defining
the operator[] to return a proxy which defines operator int() const
would do the trick very well. Before going this route, however, you
should very definitely consider all of the use cases of your class, and
ensure that there are none in which the actual target type is ambiguous.
The other answers are basically correct that you can't do it. aix hints at a solution of a custom return type with overloaded conversion operators, but rightly indicates it isn't a sane thing to do. I've ventured down this path quite often and ultimately implicit conversions, and sequences of conversions, and ambiguities will bite you in you in the behind.
I've had a need of this quite often though. Ultimately I end up going for a series of overloaded functions, or templates, depending on your needs, perhaps like this:
void lookup( int& v, char const * name );
void lookup( double& c, char const * name );
In the template case I created global converters and did the below member function:
template<T>
void lookup( T&v, char const* name ) { v = convert<T>( get(name) ); }
If you want to keep the return value as the lookup you'll have to explicitly call a templated function.
template<T> T get( char const * name ) { ... }
//use
int a = obj.get<int>( "name" );
double b = obj.get<double>( "floaty" );
No, you can't do that.
Moreso, madness that way lies!
Can I use:
MyClass& MyClass::operator++ () {
a++; // private var of MyClass
return (*this);
}
Or it can be:
MyClass MyClass::operator++ ();
What's the difference?
Thanks for answers. I have another issue.
Many people do something like that:
MyClass& MyClass::operator++();
MyClass MyClass::operator++(int);
Isn't it illogical? Please give some examples if you can.
I know that the first version is pre-increment and the second is post-increment, but i ask why the first one returns reference but the second one not? It is in the same code (class), and the same use of the code.
No, you don't have to return the reference to your object when you overload the pre-increment operator. In fact you may return anything you'd like, MyClass, int, void, whatever.
This is a design issue -- you must ask yourself what is the most useful thing to the users of your class that you are able to return.
As a general rule, class operators are the most useful when they cause the least confusion, that is, when they operate the most like operators on basic types. In this case, the pre-increment operator on a basic type:
int i = 7;
j = ++i;
increments the variable and then returns the new value. If this is the only use you want MyClass to have, then returning a copy of your class is sufficient.
But, the pre-increment operator on a basic type actually returns an lvalue. So, this is legal:
int i = 7;
int *p = &++i;
If you want to support an operation like this, you must return a reference.
Is there a specific reason that you don't want to return a reference? Is that not a well-formed concept for your particular class? If so, consider returning void. In that case, this expression: ++myObject is legal, while this myOtherObject = ++myObject is not.
You can return whatever you want. void, reference to self, copy of self, something else. Whichever you prefer (or need).
If you plan using the ++ operator in chained expressions (like (++obj).something()) then return a reference. In you don't, then void is just fine.
Remember that in the end, operators are just like normal methods: you can do whatever you want with them, provided you respect their prototype.
For question two:
Prefix returns a reference, as expected.
Postfix returns a copy to be consistent with the behavior of the postfix operator(s).
Break it down simply to int:
int c = 0;
if(++c)
{
// true, prefix increments prior to the test
}
c = 0;
if(c++)
{
// false, c now == 1, but was incremented after the test
}
Implementing this behavior in a class requires a copy be returned because the postfix operator will have modified the state of the object.
If the program does not need true postfix operation, you are free of course to implement how you wish. While there are standard ways of writing these operators (that are understood by most C++ programmers), there's nothing actually stopping you from implementing this in different ways.
The argument provided about incorrect functionality surrounding (obj++)++ is not really important, as that code won't even compile for POD types (in Visual Studio 2010, at least), because for POD types, a copy is returned and that temporary copy cannot be used alone as an l-value.
However, for the prefix operator a reference is the preferred return as that allows the proper behavior for chaining the operation (++(++obj)).
Its not compulsory, but we should try to make operator overloading intuitive and it should work as per the operator which is being overloaded.
If we do
int i = 10;
i++ = 0
Then second statement is not allowed it says it requires lvalue as i++ denotes older state of i not a storage ...
while ++i = 0 perfectly works fine ..
so just to keep it in sync with actual operators prefix version had to return refence so that its return value may be treated as lvalue in expressions.
Yes, you should return by reference. No need for the parenthesis around *this.
EDIT: Replying to your comment... You don't have to return by reference. But in general we follow some guidelines which make our classes behave "as expected" when compared to the builtin semantics of such operators. You might wanna take a look at http://www.parashift.com/c++-faq-lite/operator-overloading.html.
I'd like to overload operator[][] to give internal access to a 2D array of char in C++.
Right now I'm only overloading operator[], which goes something like
class Object
{
char ** charMap ;
char* operator[]( int row )
{
return charMap[row] ;
}
} ;
It works ok.. Is it possible to override operator[][] though?
Don’t try to do that – as others have said, overloading operator [] the way you do actually provides the [][] syntax for free. But that’s not a good thing.
On the contrary – it destroys the encapsulation and information hiding of your class by turning an implementation detail – the char* pointer – to the outside. In general, this is not advisable.
A better method would be to implement an operator [,] which takes more than one argument, or indeed an operator [][]. But neither exists in C++.
So the usual way of doing this is to ditch operator [] altogether for more than one dimension. The clean alternative is to use operator () instead because that operator can have more than one argument:
class Object
{
char ** charMap ;
char& operator ()(int row, int column)
{
return charMap[row][column];
}
};
For more information, see the article in the C++ FAQ Lite.
There is no operator [][]: that's two [] operations in a row. You could:
Have Object::operator[] return an object of a second class representing a row, which has its own operator[] method that takes a column number;
Write a get(int row, int column) method and use that instead of operator overloading. I'd recommend this unless your object absolutely has to behave like an array.
There is no operator[][]. Evaluating a[x][y] first calls operator[] on a, and then operator[] again on the result of that.
So the operator[] of your object has to return another object with its own operator[], which then will access the requested value.
As far as I know there is no such thing as operator[][]. What you can do is you could return from your operator[] method something that has overloaded operator[].
Actually you are doing it now, because you return char* which can be indexed using [] again.
There is no [][] operator. What actually happens is that the second [] operates on the variable returned by the first []. Because there is already that functionality, it would create ambiguity were there to exist a [][] operator.
For example: let's say you have a variable x of some type T.
T x = new T();
If we use the [] operator, let's say a variable of other type Q is returned:
Q y = x[0];
And then using the [] operator on a variable of type Q might return a variable of type R:
R z = y[0];
Therefore x[][] returns a variable of t ype R.
Let's say we actually were able to overload [][] for type T such that it returned a type S:
S a = x[0][0];
The compiler would have no way of knowing if it should use the [][] operator on x to return a type S variable, or use the [] operator twice in a row to return a type R variable. This is the ambiguity I mentioned above.
Your best bet if you're stuck on using square brackets is to have operator[] return a variable which also has [] overloaded (or perhaps a variable of the same type, with a flag set), and have that initially returned variable deal with the second [].
But the best solution here (as mentioned already in another answer) is to use a different operator such as ().