Beautiful C++: 30 Core Guidelines for Writing Clean, Safe, and Fast Code by J. Guy Davidson & Kate Gregory

Beautiful C++: 30 Core Guidelines for Writing Clean, Safe, and Fast Code by J. Guy Davidson & Kate Gregory

Author:J. Guy Davidson & Kate Gregory
Language: eng
Format: epub, mobi
Publisher: Addison Wesley
Published: 2022-08-15T00:00:00+00:00


Implementing a dual interface

The codebase ended up being scattered throughout with a dual interface, one of which was const and one of which was non-const. Member functions would be duplicated with const qualification, like this:

Click here to view code image

class soldier { public: commander& get_commander(); commander const& get_commander() const; };

Every soldier has a commander, but finding out who it is requires traversing quite a few objects and making a few queries. Rather than duplicating the code and the accompanying maintenance burden, it is tempting to forward to the const-qualified overload, like this:

Click here to view code image

commander& soldier::get_commander() { return const_cast<commander&>( static_cast<soldier const&>(*this).get_commander()); }

Although you are const_casting the return type, it is reasonably safe to assume that, since this is a non-const function, this is not a dangerous thing to do. It goes against the spirit of the guideline, though. Fortunately, since the introduction of trailing return types in C++11, there is a better solution:

Click here to view code image

class soldier { public: commander& get_commander(); commander const& get_commander() const; private: template <class T> static auto get_commander_impl(T& t) -> decltype(t.get_commander) { // do the work } };

The public get_commander functions simply forward to the static function template. The superior feature of this solution is that the function template knows if it is oper-ating on a soldier const object. The const qualifier is part of the type T. If the implementation breaks const, the compiler will emit an error telling you so. No cast-ing is required, and that is a good thing, since casting is ugly.

This is not always going to work, though. Consider the current_animation example:

Click here to view code image

class unit { public: animation* current_animation(); animation const* current_animation() const; private: animation* m_animation; };

You might look at this and think that the function simply returns a pointer to the animation. Sadly, it is not quite as simple as that, and there is a fair amount of logic to do with animation blending that we need to go through.

It is tempting to carry out the same trick. However, if the calling code expects to modify the animation, and the const-qualified member function does not expect the returned value, which it does not own, to be modified, we have a bug. In this case, though, it is safe to assume that the implementation of each function will be different.



Download



Copyright Disclaimer:
This site does not store any files on its server. We only index and link to content provided by other sites. Please contact the content providers to delete copyright contents if any and email us, we'll remove relevant links or contents immediately.