2009-05-04 2 views
3

오늘 아침에 모든 프로그래머가 가지고 있어야하는 기본 도구에 대한 책 The Pragmatic Programmer을 읽었으며 코드 생성 도구에 대해 언급했습니다. 이들은 C + + 프로그램 용 Perl 스크립트를 언급하면서 개인 데이터 멤버에 대한 get/set() 멤버 함수를 구현하는 프로세스를 자동화했습니다.C++ 클래스 get/set 멤버 함수를 구현할 Perl 스크립트가 있습니까?

누구나 그런 스크립트에 대해 알고 있으며 어디에서 찾을 수 있습니까? 나는 그것을 찾을 수있는 올바른 Google 키워드를 생각해 내지 못했습니다.

답변

9

직접 질문에 답변하지는 않지만 생성 된 코드가 실제로 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를 선언하지.

+0

개인 데이터 멤버와 함께 사용할 수 있습니까? – nmuntz

+1

와우! 나는 실제로 템플릿을 사용하여 속성을 에뮬레이트하고 다시 내 대답을 편집하기 위해 돌아왔다. 단지이 솔루션을 이미 여기에서 찾을 수 있으며 게시 할 간단한 해킹보다 훨씬 완벽합니다! 공유해 주셔서 감사합니다. –

+1

클래스 작성자가 클래스의 논리적 구조를 수정하지 않고 (예 : x() 메소드를 직접 작성하거나 D 구현을 변경하여) 구현을 변경할 수 있지만 바이너리 호환성이 손실되므로 사용자는 다음을 수행해야합니다. 그러한 변경이있을 때마다 클라이언트 코드를 재 컴파일하십시오. –

3

대부분의 C++ 비공개 멤버가 스타일 함수 가져 오기/설정을 통해 액세스 할 수 없으므로이 방법은 좋지 않은 것처럼 보입니다.

왜 이렇게 간단한 이유인지에 대해서는 C++ std :: string 클래스를 고려하십시오.

private: 
    int last, len; 
    char * data; 

는 당신이 사람들을 위해 GET/세트 구성원을 제공하기 위해 어떤 의미가 믿습니까 : 그 개인 회원 아마 (중요하지 정확한 구현)과 같이 보일?

+0

정말요? get/set 함수가 좋은 생각이 아니라는 것을 처음 읽은 것입니다. 왜 그것이 나쁜 생각인지 자세히 설명해 주시겠습니까? 고맙습니다! – nmuntz

+3

나는 그 질문을 이해하지 못했다고 생각합니다. 변수는 private 클래스이므로 클래스가 변경되는 방식을 제어하고 변경 사항에 반응 할 기회를 가질 수 있지만 해당 변수에 대한 공용 인터페이스는 get/set 메서드로 구현됩니다. 공용 인터페이스를 변경하지 않고 멤버를 돌연변이에 대한 컨트롤을 소급하여 추가 할 수있는 방법이없는 C++와 같은 언어에서는 전혀 잘못된 생각이 아닙니다. –

+1

나는 당신이 의미하는 것을 이해합니다. 모든 개인 데이터 멤버가 접근 자 및/또는 변경자를 가져야하는 것은 아닙니다. 그러나 어떤 방식 으로든 액세스 할 수 없도록하려는 소수의 개인 데이터 멤버에 대한 메서드를 삭제하는 것만으로도 간단합니다. 코드 생성기의 요점은 평범하고 자동화 가능한 코드를 작성하는 데 많은 시간을 소비하지 말아야한다는 것입니다. 이상적으로 언어는 회원에게 액세스 권한을 선언 할 수있게합니다. 예 : C# 속성 C++은 이것을주지 않으므로 코드 생성기를 사용하여 그 결핍을 보완합니다. –

2

해당 스크립트의 위치를 ​​알려 드릴 수 없습니다. 그러나 코드 생성 도구는 quite a lot입니다. 찾고있는 것을 이미 IDE에 포함시킬 수도 있습니다. 코드 생성 도구의 사용 방법, 사용 방법 및 이유에 대한 자세한 토론/입력을 보려면 this stackoverflow question을 참조하십시오. 나는 그 질문에 대한 대답을 좋아한다.

2

매크로 (latest version of that project)의 경우 uses Perl to augment the C preprocessor 인 한 명의 프로그래머를 알고 있습니다. 기본적인 아이디어는 당신이 게터 또는 세터를 생성 할 때 펄 스크립트에게 몇 가지 규칙을 결정할 것입니다 :

struct My_struct { 
    //set 
    //get 
    int x; 

    int y; 

    //get 
    int z; 
}; 

같은 코드 감안할 때, 나는 코멘트 "로 구성된 주석 행을 찾기 위해 스크립트를 작성할 수 있습니다 get "또는"set "을 입력 한 다음 간단한 setter/getter로 바꿉니다. 위의 예에서는 연관 멤버 변수 정의 인 뒤에 void set_x (int i), int get_x() 및 int get_z() 을 생성합니다.

경고 단어 : s ///에서이 작업을 수행하지 마십시오. 대신 각 줄을 개별적으로 스캔하고 적절한 주석 줄이 스택에 "getter/setter가 필요합니다"라는 내용을 넣은 다음 관련 멤버 변수를 볼 때 스택에서 벗어나 코드를 생성합니다 .

세부 사항에는 몇 가지 악마가 있지만 전체적으로 생각합니다.

+1

+1. 완전히 일반적인 C++ 선언을 파싱하는 것은 사실 꽤 어렵 기 때문에 Perl "전처리 기"가 비교적 간단한 선언의 하위 집합 만 인식 할 것이라고 확신합니다. 그러나 스크립트에서 수행 할 수있는 선언에 대해 공격적으로 불만을 제기하는 것이 좋습니다. 버드에있는 모든 문제를 잘게 찢어 버릴 테니까요. 빨리 실패하는 것이 좋습니다. –

+0

@j_random_hacker : 좋은 지적입니다. –

2

에 대한 get/set 함수를 생성하는 스크립트를 원한다면 모든 비공개 회원의을 무차별 적으로 생성 하시겠습니까? 그것은 매우 유용한 스크립트가 아닙니다. Google에서 찾을 수 없을 것입니다. 당신이 어떻게 든 당신의 멤버 변수에 태그를 달고 getter 및/또는 setter 스켈레톤이 자동으로 생성되게하고 싶다면, IDE 매크로가 더 적절할 것 같습니다. 그것을 위해 Google을 사용해보십시오.

관련 문제