C #에는 getter 및 setter가있는 필드에 대한 멋진 구문 설탕이 있습니다. 또한 자동 구현 속성이 마음에 듭니다.
public Foo foo { get; private set; }
C ++에서 나는 작성해야
private:
Foo foo;
public:
Foo getFoo() { return foo; }
C ++ 11에 이러한 개념이있어 이에 대한 구문 설탕을 가질 수 있습니까?
C #에는 getter 및 setter가있는 필드에 대한 멋진 구문 설탕이 있습니다. 또한 자동 구현 속성이 마음에 듭니다.
public Foo foo { get; private set; }
C ++에서 나는 작성해야
private:
Foo foo;
public:
Foo getFoo() { return foo; }
C ++ 11에 이러한 개념이있어 이에 대한 구문 설탕을 가질 수 있습니까?
답변:
C ++에서는 자신 만의 기능을 작성할 수 있습니다. 다음은 명명되지 않은 클래스를 사용하는 속성 구현의 예입니다. Wikipedia 기사
struct Foo
{
class {
int value;
public:
int & operator = (const int &i) { return value = i; }
operator int () const { return value; }
} alpha;
class {
float value;
public:
float & operator = (const float &f) { return value = f; }
operator float () const { return value; }
} bravo;
};
자체 getter 및 setter를 제자리에 작성할 수 있으며 홀더 클래스 멤버 액세스를 원하는 경우이 예제 코드를 확장 할 수 있습니다.
_alpha
개인 변수와 alpha
참조를 위해 사용합니다.
sizeof(Foo)
됩니다.
C ++에는이 기능이 내장되어 있지 않으므로 속성 기능을 모방 하는 템플릿 을 정의 할 수 있습니다 .
template <typename T>
class Property {
public:
virtual ~Property() {} //C++11: use override and =default;
virtual T& operator= (const T& f) { return value = f; }
virtual const T& operator() () const { return value; }
virtual explicit operator const T& () const { return value; }
virtual T* operator->() { return &value; }
protected:
T value;
};
속성 을 정의 하려면 :
Property<float> x;
사용자 정의 getter / setter 를 구현하려면 상속하십시오.
class : public Property<float> {
virtual float & operator = (const float &f) { /*custom code*/ return value = f; }
virtual operator float const & () const { /*custom code*/ return value; }
} y;
읽기 전용 속성 을 정의하려면 :
template <typename T>
class ReadOnlyProperty {
public:
virtual ~ReadOnlyProperty() {}
virtual operator T const & () const { return value; }
protected:
T value;
};
그리고 수업에서 사용하려면Owner
:
class Owner {
public:
class : public ReadOnlyProperty<float> { friend class Owner; } x;
Owner() { x.value = 8; }
};
더 간결하게 만들기 위해 매크로 에서 위의 일부를 정의 할 수 있습니다.
virtual
입니다 아마 속성이 다형 적 사용을 할 가능성이 있기 때문에, 대부분의 사용 사례에 대한 불필요한.
모든 플랫폼과 컴파일러에서 작동하는 C ++ 언어에는 없습니다.
그러나 크로스 플랫폼 호환성을 깨고 특정 컴파일러에 커밋하려는 경우 이러한 구문을 사용할 수 있습니다. 예를 들어 Microsoft Visual C ++에서 다음을 수행 할 수 있습니다.
// declspec_property.cpp
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
당신은 전용 유형의 멤버를 가지고와 재정 의하여 어느 정도 getter 및 setter를 에뮬레이트 할 수 operator(type)
및 operator=
그것을 위해. 그것이 좋은 아이디어인지 여부는 또 다른 질문이며 +1
Kerrek SB의 답변으로 내 의견을 표현할 것입니다. :)
friend
필드 소유자에게 a 를 추가하면 됩니다.
지난 시간 동안 내가 모은 속성 클래스를 살펴볼 수 있습니다 : /codereview/7786/c11-feedback-on-my-approach-to-c-like-class-properties
다음과 같이 동작하는 속성을 가질 수 있습니다.
CTestClass myClass = CTestClass();
myClass.AspectRatio = 1.4;
myClass.Left = 20;
myClass.Right = 80;
myClass.AspectRatio = myClass.AspectRatio * (myClass.Right - myClass.Left);
C ++ 11을 사용하면 Property 클래스 템플릿을 정의하고 다음과 같이 사용할 수 있습니다.
class Test{
public:
Property<int, Test> Number{this,&Test::setNumber,&Test::getNumber};
private:
int itsNumber;
void setNumber(int theNumber)
{ itsNumber = theNumber; }
int getNumber() const
{ return itsNumber; }
};
그리고 여기에 Property 클래스 템플릿이 있습니다.
template<typename T, typename C>
class Property{
public:
using SetterType = void (C::*)(T);
using GetterType = T (C::*)() const;
Property(C* theObject, SetterType theSetter, GetterType theGetter)
:itsObject(theObject),
itsSetter(theSetter),
itsGetter(theGetter)
{ }
operator T() const
{ return (itsObject->*itsGetter)(); }
C& operator = (T theValue) {
(itsObject->*itsSetter)(theValue);
return *itsObject;
}
private:
C* const itsObject;
SetterType const itsSetter;
GetterType const itsGetter;
};
C::*
뜻이야? 나는 전에 그런 것을 본 적이 없습니까?
C
입니다. 이것은 일반 함수 포인터와 유사하지만 멤버 함수를 호출하려면 함수가 호출되는 객체를 제공해야합니다. 이것은 itsObject->*itsSetter(theValue)
위의 예 에서 라인 을 통해 이루어집니다 . 이 기능에 대한 자세한 설명은 여기 를 참조 하십시오 .
다른 많은 사람들이 이미 말했듯이 언어에 내장 된 지원이 없습니다. 그러나 Microsoft C ++ 컴파일러를 대상으로하는 경우 문서화 된 속성에 대한 Microsoft 특정 확장을 활용할 수 있습니다. 여기 .
다음은 링크 된 페이지의 예입니다.
// declspec_property.cpp
struct S {
int i;
void putprop(int j) {
i = j;
}
int getprop() {
return i;
}
__declspec(property(get = getprop, put = putprop)) int the_prop;
};
int main() {
S s;
s.the_prop = 5;
return s.the_prop;
}
아니요, C ++에는 속성 개념이 없습니다. getThis () 또는 setThat (value)를 정의하고 호출하는 것이 어색 할 수 있지만 이러한 메서드의 소비자에게 일부 기능이 발생할 수 있다는 설명을하고 있습니다. 반면에 C ++에서 필드에 액세스하면 추가 또는 예상치 못한 기능이 발생하지 않는다는 것을 소비자에게 알립니다. 속성 액세스는 언뜻보기에 필드처럼 반응하는 것처럼 보이지만 실제로는 메서드처럼 반응하므로 속성은이를 덜 명확하게 만듭니다.
제쳐두고 저는 고객 멤버십 시스템을 만들려고 시도하는 .NET 응용 프로그램 (아주 잘 알려진 CMS)에서 작업하고있었습니다. 사용자 개체에 대한 속성을 사용하는 방식으로 인해 예상치 못한 작업이 실행되어 무한 재귀를 포함하여 기이 한 방식으로 구현이 실행되었습니다. 이는 사용자 개체가 StreetAddress와 같은 간단한 항목에 액세스하려고 할 때 데이터 액세스 레이어 또는 일부 글로벌 캐싱 시스템을 호출했기 때문입니다. 그들의 전체 시스템은 내가 재산 남용이라고 부르는 것에 기반을두고 있습니다. 속성 대신 메서드를 사용했다면 무엇이 잘못되었는지 훨씬 더 빨리 파악했을 것입니다. 그들이 필드를 사용했다면 (또는 적어도 그들의 속성이 필드처럼 동작하도록 만들었 더라면) 시스템을 확장하고 유지하는 것이 더 쉬웠을 것입니다.
[편집] 내 생각을 바꿨습니다. 나는 나쁜 하루를 보냈고 약간의 호언을했다. 이 정리는 더 전문적이어야합니다.
https://stackoverflow.com/a/23109533/404734를 기반으로 여기에 공개 getter 및 private setter가있는 버전이 있습니다.
struct Foo
{
class
{
int value;
int& operator= (const int& i) { return value = i; }
friend struct Foo;
public:
operator int() const { return value; }
} alpha;
};
이것은 정확히 속성은 아니지만 간단한 방법으로 원하는 것을 수행합니다.
class Foo {
int x;
public:
const int& X;
Foo() : X(x) {
...
}
};
여기서 큰 X public int X { get; private set; }
는 C # 구문 에서처럼 동작 합니다. 본격적인 속성을 원한다면 여기 에서 구현하는 첫 번째 샷을 만들었습니다 .
X
새 개체 의 참조 는 포인터 멤버처럼 복사되기 때문에 이전 개체의 멤버를 계속 가리 킵니다. 이것은 그 자체로 나쁘지만 오래된 개체가 삭제되면 그 위에 메모리 손상이 발생합니다. 이 작업을 수행하려면 자체 복사 생성자, 할당 연산자 및 이동 생성자를 구현해야합니다.
당신은 아마 그것을 알고있을 것입니다. 그러나 저는 단순히 다음과 같이 할 것입니다.
class Person {
public:
std::string name() {
return _name;
}
void name(std::string value) {
_name = value;
}
private:
std::string _name;
};
이 접근 방식은 간단하고 영리한 트릭을 사용하지 않으며 작업을 완료합니다!
문제는 일부 사람들이 자신의 개인 필드 앞에 밑줄을 붙이는 것을 좋아하지 않아서이 접근 방식을 실제로 사용할 수 없다는 것입니다.하지만 다행히도 그렇게하는 사람들에게는 정말 간단합니다. :)
get 및 set 접두사는 API에 명확성을 추가하지 않지만 더 장황하게 만들고 유용한 정보를 추가하지 않는다고 생각하는 이유는 API가 합리적이면 누군가 API를 사용해야 할 때 API가 무엇인지 알 수 있기 때문입니다. 접두사없이합니다.
한 가지 더, 이것들이 속성이라는 것을 이해하기 쉽습니다. name
동사가 아니기 .
최악의 시나리오는 API가 일관되고 사용자가 그것이 name()
접근 자이고name(value)
뮤 테이터 , 패턴을 이해하기 위해 문서에서 한 번만 조회하면됩니다.
C #을 좋아하는만큼 C ++에 속성이 전혀 필요하지 않다고 생각합니다!
foo(bar)
(느린 대신) 사용하면 의미가 foo = bar
있지만 접근자는 속성과 전혀 관련이 없습니다 ...
foo(bar)
사용 하여 대신 초기화 foo=bar
할 수 있기 때문입니다 . void foo(Bar bar)
_foo
여러 C ++ 소스에서 아이디어를 수집하여 C ++의 getter / setter에 대한 훌륭하고 여전히 매우 간단한 예제에 넣었습니다.
class Canvas { public:
void resize() {
cout << "resize to " << width << " " << height << endl;
}
Canvas(int w, int h) : width(*this), height(*this) {
cout << "new canvas " << w << " " << h << endl;
width.value = w;
height.value = h;
}
class Width { public:
Canvas& canvas;
int value;
Width(Canvas& canvas): canvas(canvas) {}
int & operator = (const int &i) {
value = i;
canvas.resize();
return value;
}
operator int () const {
return value;
}
} width;
class Height { public:
Canvas& canvas;
int value;
Height(Canvas& canvas): canvas(canvas) {}
int & operator = (const int &i) {
value = i;
canvas.resize();
return value;
}
operator int () const {
return value;
}
} height;
};
int main() {
Canvas canvas(256, 256);
canvas.width = 128;
canvas.height = 64;
}
산출:
new canvas 256 256
resize to 128 256
resize to 128 64
여기에서 온라인으로 테스트 할 수 있습니다. http://codepad.org/zosxqjTX
기록 된 매크로 세트가 있습니다 여기에 . THis에는 값 유형, 참조 유형, 읽기 전용 유형, 강력한 유형 및 약한 유형에 대한 편리한 속성 선언이 있습니다.
class MyClass {
// Use assign for value types.
NTPropertyAssign(int, StudentId)
public:
...
}