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
Somethingelement, 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
returnstatement.)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 owntemplateclass explicitly instead, please say what that should look like and why it is preferable to my way.] -
return QList<Something>::operator[](index) -
@J-Hilk
Hmph, yes, I forget I can do that.
Do you really thinkQList<Something>::operator[](index)is "nicer" than(*this)[someIndex]though? :) I find it longer to type and read and (maybe) understand.@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?
-
@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]; -
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.... -
Oh I see!
Well, I personally would prefere:
auto pqr = operator[](index);over
auto mno = (*this)[index];@J-Hilk
UPDATE:
I chanced having a look in online Qt source code ofQStringListin 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
UPDATE:
I chanced having a look in online Qt source code ofQStringListin 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+pandarray+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 capturessomeIndexby 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 nameselfis derived from other OO languages that use a referenceselfto the object instead of a pointerthis.)