Subclassing where parent class has `[]` operator
-
I create some specialized list classes holding elements of some class. I might add add member variables and/or methods.
class SomethingList : public QList<Something> { ... }
If some method wants to return some
Something
element, usingat(i)
I can write it "plain" like:return at(someIndex);
(and similarly call e.g.
count()
just like that, etc.) Or at a pinch I could usereturn this->at(someIndex)
if I prefer.But when I need to use the T &QList::operator[](int i)
[]
operator, C++ does not allow:return [someIndex];
nor
this->[someIndex]
. I have found I need to write:return (*this)[someIndex];
(And of course this is not limited to a
return
statement.)It's OK and it compiles and works, I just feel it looks a bit "odd". Any comment on this? Is what I have just how it has to be?
[Btw, on presumably a separate matter. I am very happy declaring and working with
class SomethingList : public QList<Something>
. If someone is going to say I should not do this and should write it as my owntemplate
class explicitly instead, please say what that should look like and why it is preferable to my way.] -
return QList<Something>::operator[](index)
-
@JonB said in Subclassing where parent class has `[]` operator:
(*this)[someIndex]
I would assume this is a recursive call, right? why should this default to the base class implementation?
-
@J-Hilk said in Subclassing where parent class has `[]` operator:
recursive call, right
You misunderstand. I never said I am overriding the (virtual)
[]
operator in my subclasses. I am not. I am simply trying to invoke the[]
operator in some method within the subclass:SomethingList::someMethod() { auto abc = count(); // works, as would this->count() auto def = at(10); // works, as world this->at(10) auto ghi = [10]; // does not work auto jkl = this->[10]; // does not work auto mno = (*this)[10]; // works, and is what I currently use // next two are yours, I have not tested whether work // but personally I find them uglier/just as ugly as (*this)[10] ? auto pqr = QList<Something>::operator[](10); auto stu = SomethingList::operator[](10); }
-
Oh I see!
Well, I personally would prefere:
auto pqr = operator[](index);
over
auto mno = (*this)[index];
-
@J-Hilk
Fair enough. In your last example I see we could drop theQList<Something>::
orSomethingList::
prefix and just write plainoperator[](index)
, that is an improvement for me.I'm not sure whether I agree with your preference, but maybe you are "correcter" ;-) (I like seeing
[index]
somewhere in my expression!) If you don't mind, I should like to see whether anyone else would care to comment/express a preference here, before I mark yours as correct answer. If everyone else says yours is "the way to write it in C++" I will change over.... -
@J-Hilk
UPDATE:
I chanced having a look in online Qt source code ofQStringList
in the hope of finding where they might try to call[]
. At https://codebrowser.dev/qt5/qtbase/src/corelib/text/qstringlist.cpp.html#539 I find(*that)[i].replace(before, after, cs);
I realise this code is with a
that
(for anotherQStringList
) rather than with athis
, but note that it uses the(*something)[i]
syntax. So I am not alone..... -
@J-Hilk
...which is prolly exactly why it's more to my taste... ;-)As in: If it's C you can just look at it and tell just what it does. If it's C++ you can look at it, and if you understand it at all and think you know what it does, it probably does something else/much more....
-
Well, first of all (user-defined) operators in C++ are just functions. Hence, it means you can call them using the function syntax (like mentioned as
operator[](someIndex)
). To understand why you cannot just write[someIndex]
we need to look at the history of C++; or rather C. We get the index operator syntax from plain arrays and pointers. These require the array or pointer to be explicitly written before the operator:p[i]
orarray[i]
. (To be more precise: These are the same asi[p]
andi[array]
because officially in C these are equivalent top+i
=i+p
andarray+i
=i+array
. However, this weird syntax does not work for operator[] overloading and doesn't help to make my point.) In the same way you need to write the object on which to call the overloaded operator[] in front of the index access. If you could use implicit this, the same would need to apply e.g. for the binaryoperator+
and the like. What aboutoperator=
? I personally also think that just[someIndex]
is not really readable. It doesn't show directly that you want to use an index operator. I prefer that you must write(*this)[someIndex]
explicitly. In most places I would use it like this. Only when I want to make plain that I want to forward to operator[] (as was initially asked) I would make the forwarding aspect clear by writingoperator[](someIndex)
.Furthermore, now it is too late to introduce the short-hand syntax (implicit this) into C++.
[]
without an object preceeding it is already reserved for introducing lambdas. I would expect that the compiler error forreturn [someIndex];
would say something along the lines that the body for the lambda function is missing. (return [someIndex]{};
would return a lambda that does nothing, but capturessomeIndex
by value. Function arguments()
are optional for lambdas if they are empty.)Sometimes when I need to use some operators (not necessarily the index operator) several times inside a member function (and I'm annoyed at writing
(*this)
over and over again) I would writeauto &self = *this;
. Then, it is much nicer to writereturn self[someIndex];
. (The nameself
is derived from other OO languages that use a referenceself
to the object instead of a pointerthis
.)