An elegant solution for duplication, const and non-const, getters?

Do not hate when you

class Foobar { public: Something& getSomething(int index) { // big, non-trivial chunk of code... return something; } const Something& getSomething(int index) const { // big, non-trivial chunk of code... return something; } } 

We cannot implement any of these methods with another, because you cannot call the const version from the const version (compiler error). To cast a version of const from non-t21> rendering is required.

Is there a real elegant solution for this, if not, which is closest to it?

+98
c ++ const
May 13 '09 at 7:25 a.m.
source share
8 answers

I remember from one of the effective books in C ++ that the way to do this is to implement the non-constant version by dropping the const from another function.

It is not particularly beautiful, but safe. Since the member function calling it is not a constant, the object itself is not a constant, and dropping a constant is allowed.

 class Foo { public: const int& get() const { //non-trivial work return foo; } int& get() { return const_cast<int&>(static_cast<const Foo*>(this)->get()); } }; 
+88
May 13 '09 at 8:48 a.m.
source share

What about:

 template<typename IN, typename OUT> OUT BigChunk(IN self, int index) { // big, non-trivial chunk of code... return something; } struct FooBar { Something &getSomething(int index) { return BigChunk<FooBar*, Something&>(this,index); } const Something &getSomething(int index) const { return BigChunk<const FooBar*, const Something&>(this,index); } }; 

Obviously, you will still have duplicate object code, but no duplication of source code. Unlike the const_cast approach, the compiler checks for your const validity for both versions of the method.

You probably need to declare two interesting instances of BigChunk as friends in this class. This is a good use of a friend, since the friend’s functions are hidden next to each other, so there is no risk of unconditional communication (ooh-er!). But I will not try to use the syntax for this right now. Feel free to add.

Most likely, BigChunk should respect itself, and in this case the above determination procedure will not work very well, and some forward declarations will be required to sort it.

In addition, to avoid the BigChunk multiple search in the header and making a decision about creating an instance and invoking it even if it is morally closed, you can move the entire batch to the cpp file for FooBar. In an anonymous namespace. With an internal connection. And the sign saying "beware of the leopard."

+25
May 13 '09 at 16:14
source share

I would include const in non-constant (second option).

+7
May 13 '09 at 7:34 a.m.
source share

Try eliminating getters by refactoring the code. Use friends functions or classes if only a small number of other things need something.

As a rule, Getters and Setters break encapsulation because data enters the world. Using a friend only provides data to several, so it gives better encapsulation.

Of course, this is not always possible, so you can get stuck with getters. At least most or all of the "nontrivial code snippets" must be in one or more private functions called by both getters.

+6
May 13 '09 at 7:50
source share

Why not just put the common code in a separate private function, and then call the other two calls?

+6
May 13, '09 at 16:43
source share

The concept of "const" exists for some reason. For me, he establishes a very important contract, on the basis of which further instructions of the program are written. But you can do something along the following lines: -

  • make your dick "volatile"
  • make 'getters' const
  • returns a non-constant link

In this case, you can use the const reference to LHS if you need to support the const function when you use getter together with non-constant use (dangerous). But the burden of responsibility is now on the programmer to preserve class invariants.

As already mentioned in SO, expelling the constant of the originally given const object and using it is UB Therefore, I would not use a cast. Also, creating a non-constant const object and then dropping the constant again would not look too good.

Another coding guide I've seen in some commands is: -

  • If a member variable needs to be changed outside the class, always return a pointer to it using the non-const member function.
  • No member functions can return non-constant references. Only const references are allowed in the form of constant functions.

This allows for some consistency in the common code base, and the caller can clearly see which calls the member variable can modify.

+3
May 13 '09 at 7:51 a.m.
source share

A reference to a const object makes sense (you restrict read-only access to this object), but if you need to allow a non- const link, you can also make a member of the public.

I believe this is Scott Myers (Efficient C ++).

+3
May 13 '09 at 7:55 a.m.
source share

I suggest using a preprocessor:

 #define ConstFunc(type_and_name, params, body) \ const type_and_name params const body \ type_and_name params body class Something { }; class Foobar { private: Something something; public: #define getSomethingParams \ ( \ int index \ ) #define getSomethingBody \ { \ return something; \ } ConstFunc(Something & getSomething, getSomethingParams, getSomethingBody) }; 
-one
Jan 29
source share



All Articles