IT박스

const, non-const, getter를 복제하는 우아한 솔루션?

itboxs 2020. 7. 29. 07:58
반응형

const, non-const, getter를 복제하는 우아한 솔루션? [복제]


당신이 그것을 할 때 그것을 싫어하지 마십시오

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;
    }
}

const버전에서 버전을 호출 할 수 없으므로 const(컴파일러 오류) 이 방법 중 하나를 다른 방법으로 구현할 수 없습니다 . const비 버전에서 버전 을 호출하려면 캐스트가 필요합니다 const.

그렇지 않은 경우 가장 가까운 솔루션은 무엇입니까?


필자는 효과적인 C ++ 서적 중 하나에서 const를 다른 함수에서 캐스팅하여 비 const 버전을 구현하는 방법을 기억합니다.

특히 예쁘지는 않지만 안전합니다. 그것을 호출하는 멤버 함수는 비 const이기 때문에 객체 자체는 비 const이며 const를 캐스팅하는 것이 허용됩니다.

class Foo
{
public:
    const int& get() const
    {
        //non-trivial work
        return foo;
    }

    int& get()
    {
        return const_cast<int&>(const_cast<const Foo*>(this)->get());
    }
};

어때요?

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);
    }
};

분명히 객체 코드 복제는 유지되지만 소스 코드 복제는 없습니다. const_cast 방식과 달리 컴파일러는 두 버전의 메소드에 대한 const-correctness를 확인합니다.

BigChunk의 흥미로운 두 가지 인스턴스를 클래스의 친구로 선언해야 할 것입니다. 프렌드 기능이 프렌 디 근처에 숨겨져 있기 때문에 프렌드를 잘 사용하므로 제한되지 않은 커플 링 (ooh-er!)의 위험이 없습니다. 그러나 나는 지금 그렇게하는 구문을 시도하지 않을 것입니다. 자유롭게 추가하십시오.

Chances are that BigChunk needs to deference self, in which case the above order of definition isn't going to work very well, and some forward declarations will be needed to sort it out.

Also, in order to avoid some numpty finding BigChunk in the header and deciding to instantiate and call it even though it's morally private, you can move the whole lot into the cpp file for FooBar. In an anonymous namespace. With internal linkage. And a sign saying "beware of the leopard".


I would cast the const to the non-const (second option).


Why not just pull the common code out into a separate, private function, and then have the other two call that?


Try to eliminate the getters by refactoring your code. Use friend functions or classes if only a very small number of other things needs the Something.

In general, Getters and Setters break encapsulation because the data is exposed to the world. Using friend only exposes data to a select few, so gives better encapsulation.

Of course, this is not always possible so you may be stuck with the getters. At the very least, most or all of the "non-trivial chunk of code" should be in one or more private functions, called by both getters.


The const reference to the object makes sense (you're putting a restriction on read-only access to that object), but if you need to allow a non-const reference, you might as well make the member public.

I believe this is a la Scott Meyers (Efficient C++).


The concept of 'const' is there for a reason. To me it establishes a very important contract based on which further instructions of a program are written. But you can do something on the following lines :-

  1. make your member 'mutable'
  2. make the 'getters' const
  3. return non-const reference

With this, one can use a const reference on the LHS if you need to maintain the const functionality where you are using the getter along with the non-const usage(dangerous). But the onus is now on the programmer to maintain class invariants.

As has been said in SO before, casting away constness of an originally defined const object and using it is an U.B. So i would not use casts. Also making a non-const object const and then again casting away constness would not look too good.

Another coding guideline that I have seen used in some teams is:-

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

This allows some consistency in the overall codebase and the caller can clearly see which calls can modify the member variable.


I dare suggest using the 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)
};

참고URL : https://stackoverflow.com/questions/856542/elegant-solution-to-duplicate-const-and-non-const-getters

반응형