직접 질문에 답변하지는 않지만 생성 된 코드가 실제로 C++의 속성을 관리하는 데 필요하지 않음을 알 수 있습니다. 다음 템플릿 코드가 편리 선언하고 사용 등록 할 수 있습니다 : 여기
// Declare your class containing a few properties
class my_class {
public:
property<int> x;
property<string> y;
...
};
...
my_class obj;
cout << obj.x(); // Get
obj.y("Hello, world!"); // Set
코드입니다 :
// Utility template to choose the 2nd type if the 1st is void
template <typename T, typename U>
struct replace_void {
typedef T type;
};
template <typename T>
struct replace_void<void, T> {
typedef T type;
};
// Getter/setter template
template <typename T, typename D = void>
class property {
typedef typename replace_void<D, property>::type derived_type;
derived_type& derived() { return static_cast<derived_type&>(*this); }
public:
property() {} // May be safer to omit the default ctor
explicit property(T const& v) : _v(v) {}
property(property const& p) : _v(p._v) {}
property& operator=(property const& p) { _v = p._v; return *this; }
T operator()() const { return _v; } // Getter
void operator()(T const& v) { derived().check(v); _v = v; } // Setter
protected:
// Default no-op check (derive to override)
void check(T const& v) const { (void)v; //avoid unused variable warning}
private:
T _v;
};
check()
는 할당되는 값이 유효한지 여부를 테스트하는 기능입니다. 당신은 하위 클래스에서 재정의 할 수 있습니다
이
class nonnegative_int : public property<int, nonnegative_int> {
public:
// Have to redeclare all relevant ctors unfortunately :(
nonnegative_int(int v) : property<int, nonnegative_int>(v) {}
void check(int const& v) const {
if (v < 0) {
throw "Yikes! A negative integer!";
}
}
};
당신이 그것을 가지고 - 외부에서 생성 된 게터/세터 기능의 장점을 모두 혼란 하나도 없다! :)
check()
은 예외를 throw하는 대신 유효성을 나타내는 bool
을 반환 할 수 있습니다. 원칙적으로 유사한 메소드 인 access()
을 추가하여 속성에 대한 읽기 참조를 포착 할 수 있습니다.
EDIT 씨 Fooz은 코멘트 노츠는 클래스 저작 나중에 이진 않지만, (x()
방법 쌍으로 property<int> x
부재로 대체함으로써 예) 클래스의 논리적 구성을 변경하지 않고 구현을 변경할 수 호환성이 없어 지므로 사용자는 그러한 변경이있을 때마다 클라이언트 코드를 다시 컴파일해야합니다. 미래의 변경 사항을 손쉽게 통합 할 수있는이 기능은 실제로 사람들이 처음에는 공용 멤버 대신 getter/setter 함수를 사용하는 주된 이유입니다.
성능 주 : 우리가 달성하기 위해 CRTP을 사용하고 있기 때문에 "컴파일 타임 다형성은"서브 클래스에 check()
자신의를 제공하기위한 가상 호출 오버 헤드가 없다, 당신은 필요 그것을 virtual
를 선언하지.
개인 데이터 멤버와 함께 사용할 수 있습니까? – nmuntz
와우! 나는 실제로 템플릿을 사용하여 속성을 에뮬레이트하고 다시 내 대답을 편집하기 위해 돌아왔다. 단지이 솔루션을 이미 여기에서 찾을 수 있으며 게시 할 간단한 해킹보다 훨씬 완벽합니다! 공유해 주셔서 감사합니다. –
클래스 작성자가 클래스의 논리적 구조를 수정하지 않고 (예 : x() 메소드를 직접 작성하거나 D 구현을 변경하여) 구현을 변경할 수 있지만 바이너리 호환성이 손실되므로 사용자는 다음을 수행해야합니다. 그러한 변경이있을 때마다 클라이언트 코드를 재 컴파일하십시오. –