What should I choose from the below functions - c++

suppose I design a String class myself and I want to overload the operator[] functions, here are the choices:
String operator[](const size_t index);
String& operator[](const size_t index);
const String& operator[](const size_t index) const;
any other combination of const, non-const and reference return type.

The [] operator of a string returns a character, not a string. Depending on circumstances, you should implement one or two of them:
const char& operator[] ( size_t index ) const;
char& operator[] ( size_t index );
The first one produces a reference that cannot be modified. If your string is immutable, that is all you need.
The second one produces a reference that can be modified. You can use it to implement clever stuff, such as copy-on-modify and reference counting.

Some people prefer to have a signed parameter type for operator[], both to be more similar to built-in operator[] (they too support negative indices) and also to be able to detect negative value arguments (in case you have an out of bounds check).
The type that the C++ compiler uses to evaluate calling the built-in operator[] is ptrdiff_t, so you will sometimes find the following
char &operator[](ptrdiff_t index);
char operator[](ptrdiff_t index) const;
I usually just use a plain int parameter type.

Related

How can I overload operator[] to allow for `object[a] = b`?

It's possible to overload operator[] to take one argument, in the brackets. However how can I overload this operator to allow the user to type object[a] = b?
You return a reference to your item, something like:
A &operator[](int pos) { return list[pos]; }
So when you say object[a]=b; it's actually translated to:
A &tmp=object[a];
tmp=b;
Or in more clear terms:
A *tmp=object[a]; // more or less a pointer
*tmp=b; // you replace the value inside the pointer
The general declaration of the operator (it shall be a class member function) is the following
ObjectElementType & operator []( size_t );
Subscript operators often comes in pair :-
T const& operator[] (size_t ) const;
T& operator[] (size_t ); // This enables object[a] = b on non-const object

Giving preference to one operator[] over another

Consider the following class:
class Test
{
public:
Test( char );
Test( int );
operator const char*();
int operator[]( unsigned int );
};
When I use it:
Test t;
Test& t2 = t[0];
I get a compiler error where it can't figure out which operator[] to use. MSVC and Gcc both. Different errors. But same problem.
I know what is happening. It can construct a Test from either an int or a char, and it can either use Test::operator[] or it can cast to const char* and use the built char*[].
I'd like it to prefer Test::operator[].
Is there a way to specify a preference like this?
UPDATE: First, I'll agree with response below that there is no language feature that lets you specify a priority for conversions. But like juanchopanza found below - you can create such a preference indirectly by making one conversion require no casts, and make the other require a cast. E.g. unsigned int as the argument for operator[] won't work but, using int will.
The default index argument is unsigned - for gcc and msvc anyway - so making the index argument unsigned will cause the compiler to prefer the right operator.
#Konrad: about implicit conversions to built-in types. Agree generally. But I need it in this case.
No there isn't. And this kind of ambiguity is why automatic conversions to another type (like operator char*) are not recommended.
You can always make the constructors explicit – or, as john has noted, omit the conversion operator. I’d usually recommend doing all of these things but since your code is a toy example it’s hard to say what is appropriate in your situation.
That said, the following should work:
Test const& t2 = t.operator[](0);
(Note the added const – otherwise you’d bind a temporary to non-const reference which doesn’t work either.)
I've implemented container classes like yours before -- it is entirely possible to avoid ambiguity problems while maintaining a clean, intuitive syntax.
First, you need to take const-ness into account. Usually, a const char* cast will not modify the object, so make this a const member function:
operator const char*() const;
Also, your [] operator is returning an int instead of int&, so this should probably be const too:
int operator[]( unsigned int ) const;
If you want to be able to assign a value to an indexed element (mytest[5]=2), you would add another operator function like this (this doesn't replace the const version above -- keep both):
int& operator[](unsigned int);
Next, you will want to accept indexes that are not just unsigned int. A literal integer has the int type. To avoid problems related to index type, you need to overload operator for alternatives. These overloads will just static_cast the index to your native index type and pass it to the native overload (the one for the native index type). One of these overloads might look like:
int operator[]( int idx ) const {
return operator[]( static_cast<unsigned int>(idx) );
}
Instead of adding a bunch of overloads, you could use a single template member function to cover all possibilities. The template function will get used for any index types that do not already have a non-template overload. And this preference for non-template overloads is unambiguous. Essentially, this implements your request for a preferred operator, but const-ness is not templatable, so two versions would be required if you have a const and a non-const [] operator. This catch-all member function might look like this (keep in mind that its definition must stay in your class' declaration and cannot be moved to an implementation file):
template <typename IT>
int operator[]( const IT& idx ) const {
return operator[]( static_cast<unsigned int>(idx) );
}
If you added a non-const version of the [] operator, then you would also need:
template <typename IT>
int& operator[]( const IT& idx ) {
return operator[]( static_cast<unsigned int>(idx) );
}
Enjoy!

Class storing pointers to vector in C++

I'm implementing a class Aviary, which can store pointers to Bird-objects. Now, I have the following:
class Aviary {
public:
const Bird &operator[](const size_t index) const {
return birds[index];
}
Bird &operator[](const size_t index) {
return birds[index];
}
private:
std::vector<Bird*> birds;
The Bird-objects are stored as pointers in order to avoid object-slicing. However, there is a problem with the operator[]-implementation (Reference to type 'const Bird' could not bind to an lvalue of 'const value_type' (aka 'Bird *const')).
How do I implement the operator[] properly?
Since you store pointers, you should dereference the pointer for return reference.
const Bird &operator[](const size_t index) const {
return *birds[index];
}
Bird &operator[](const size_t index) {
return *birds[index];
}
Side note: use smart pointers, instead of raw pointers.
Two side notes:
The const in a parameter passed by value (const size_t index) is useless and your compiler will ignore it. You can try declaring it with const and removing the const in the implementation: the compiler will correctly consider that your implementation matches the declaration.
The canonical way to implement the non-const version of operator[] is as follows:
As follows
Bird &operator[](size_t index) {
return const_cast<Bird&>(const_cast<const Aviary*>(this)->operator[](index));
}
I know all those const_cast look ugly, but they are both safe and this is the right way to ensure that both versions of operator[] do the same (you just need to maintain the const version from now on), while also making sure that your are not doing any non-const operation in the const version.
Apart from that, the problem with your code is that you are returning pointers, not (references to) the values pointed by them, as Luchian and ForEveR have already pointed out.
You need to dereference:
return *(birds[index]);
birds[index] is a Bird*, so you can't directly return it as a Bird&.

why sometime a function return a const, or const reference

First, why return const?
say I have
friend const MyVec operator-(const MyVec& left, const MyVec& right)
so is returning const makes me cannot do:
mva - mvb = mvc;
Second, why return const reference?
if there is:
friend const MyVec& operator++(MyVec& v)
with const I cannot: (++mva) = mvc
if it is
MyVec& operator++(MyVec& v)
I can:++(++mva) // with increment twice.
am I understanding right?
There is not any good reason to return a const object. However, there are many good reasons to return pointers or references to const objects.
The program might have an object that is very expensive to copy, so it returns a reference. However, the object should not be changed through that reference. For example, it might be part of a sorted data structure and if its values were modified it would no longer be sorted correctly. So the const keeps it from being modified accidentally.
Arithmetic operator functions should not return const objects, because of exactly the problems in your question.
Dereferencing an iterator should return a const reference. That is if it is operating on a collection of const objects or possibly on a const collection. This is why class functions sometimes have two copies of a function with the second copy using a const on the function itself, like this:
T& operator[](size_t index);
const T& operator[](size_t index) const;
The first function would be used on non-const objects and the second function would be used for const objects.
Yes your understanding is correct. To avoid accidental assignments, one can return an object by const or const reference.
With operator -, you return an object by value. To avoid it getting edited accidently, one can return by const value, because anyways the object will be mostly a temporary.
For operator ++, conventionally it returns reference, however to avoid situations as (++ x) = y; you can return it by const reference.

C++: "const" in front of a class method

Taking for example this method declaration:
const Vector Vector::operator - ( const Vector& other ) const;
I know that the second const makes the Vector passed as an argument immutable, and that the last const declares that the method does not change the current instance of the Vector class....
But what exactly does the first const mean or lead to?
It is an outdated security measure to prevent nonsense code like a - b = c to compile.
(I say "outdated" because it prevents move semantics which only works with non-const rvalues.)
The first const means that this operator will return a constant Vector object.
It means the return value is a const Vector.
It has more meaning in cases such as this: const int& Vector::get(int index) const;