Path: csiph.com!news.mixmin.net!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c++ Subject: Re: Virtual functions: To const, or not to const? Date: Mon, 10 Oct 2022 09:43:26 -0700 Organization: A noiseless patient Spider Lines: 58 Message-ID: <86zge3hbo1.fsf@linuxsc.com> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader01.eternal-september.org; posting-host="3c67835d7e1bd6fce16ecef79276b22a"; logging-data="900710"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19KCxR1E2MsmdEFGzD/ZpiG1k3g5jV1AJg=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:PinctmGFptKe5WTQMNw3mBkH3Tc= sha1:499Bn0/wzUpyRkp9IxU7Vl1gmZQ= Xref: csiph.com comp.lang.c++:86859 Paavo Helde writes: > 10.10.2022 09:20 Juha Nieminen kirjutas: > >> David Brown wrote: >> >>> Shouldn't it be a matter of deciding whether the function logically >>> changes the object or not? If it clearly changes the object, it must be >>> non-const. But if it leaves the object with the same publicly visible >>> state, make it const. Any later bits that might need changing should be >>> mutable. >>> >>> A virtual function is an interface, not implementation detail. It >>> doesn't make sense to me to have a virtual function that is logically >>> const in a base class, but logically non-const in a derived class. >> >> There are situations where the base class function is *so* abstract that >> it doesn't even express if the derived class implementations should be >> mutable or const. Some derived classes might want to implement as a >> non-const function, other derived classes as a const function (so that >> it can be called with const objects/references). > > If that's really so, then it looks like you have got two different > class hierarchies or at least two interfaces, not one. Right. I was wondering how long it would be before someone would reach this conclusion. Here is an outline for a scheme that supplies each of the four logically distinct possibilities: struct super_neither { protected: unsigned u_; public: super_neither() : u_(0) {} virtual ~super_neither(); }; struct super_mutable_only : public virtual super_neither { virtual unsigned u() { return ++u_; } }; struct super_nonmutable_only : public virtual super_neither { virtual unsigned u() const { return 1+u_; } }; struct super_both : public super_mutable_only, super_nonmutable_only { virtual unsigned u() { return super_mutable_only::u(); } virtual unsigned u() const { return super_nonmutable_only::u(); } }; Different subclasses should choose whichever of the four given superclasses that is most appropriate to their individual needs. Disclaimer: code intended only to illustrate the approach; some details may need changing, depending on particular circumstances.