같은 멤버이지만 이름이 다른 두 개의 구조체는 좋은 생각입니까?


49

극좌표와 데카르트 좌표로 작업하는 프로그램을 작성 중입니다.

그것은 감각 점, 하나의 각 종류의 두 개의 서로 다른 구조체를 만들 수 있습니까 XY회원들과 하나가 함께 R하고 Theta회원.

또는 너무 많이이며 함께 한 구조체를하는 것이 좋습니다 firstsecond회원으로.

내가 쓰고있는 것은 간단하며 크게 바뀌지 않습니다. 그러나 디자인 관점에서 더 나은 점이 궁금합니다.

첫 번째 옵션이 더 낫다고 생각합니다. 더 읽기 쉽고 유형 검사의 이점을 얻습니다.


11
나는 항상 목적마다 새로운 구조체 / 클래스를 만듭니다. 3D 벡터가 필요하고 3 개의 float로 구조체 3d_vector를 만듭니다. uvw 표현이 필요하고 3 개의 float로 구조체 texture_coords를 만듭니다. 3D 환경에서 위치가 필요하고 3 개의 부동 소수점으로 구조체 위치를 만듭니다. 당신은 요점을 얻습니다. 그것은 같은 것을 사용하는 것보다 훨씬 더 나은 가독성을 허용합니다. 동일한 것을 여러 번 정의하여 방해하는 경우 기본 3-float-struct를 사용하고 여러 이름을 동일한 구조로 정의하십시오.
케빈

그들이 일반적인 방법을 가지고 있다면 아마도 하나 일 것입니다. 이 둘의 평등을 비교해야합니까?
paparazzo

8
@Sidney 내가 원하지 않는 기능이 절대적으로 필요하지 않으면. 두 표현 사이를 변환하려면 sin / arcsin 연산을 수행해야합니다. 이것은 변환을 할 때마다 최하위 비트에 비트 비트를 도입합니다. 나는 당신이 이벤트 빈도와 이벤트 사이의 시간 (x와 1 / x)을 제공하는 클래스를 다루려고했던 것과 비슷한 고통을 겪을 것이라고 거의 확신합니다. 어떤 표현이 수업에서 정직하지 않은지 추적하고 모든 반올림 두통을 다루는 것은 다시하고 싶은 것이 아닙니다.
Dan Neely

3
많은 것을 나타낼 수있는 데이터 유형의 좋은 예는 문자열이지만 "문자열 유형"은 반 패턴입니다. 예를 들어 두 좌표계를 모두 지원하는 유형에 대해 내적을 구현하십시오.
Nathan Cooper

1
적용 가능한 경우 항상 다른 유형을 사용하여 유형 안전의 이점을 얻으려고 노력해야합니다. 이렇게하면 프로그래밍 언어에 따라 컴파일 시간 정확성 검사를 사용하여 함수에 잘못된 유형을 보내지 못하게됩니다. 어떤 유형의 실제 사용을 찾을 수 있기 때문에 유지 보수가 쉬워집니다 (유형이 잘못되어 잘못 사용되지 않음).
Erik Eidt

답변:


17

두 솔루션을 모두 보았으므로 상황에 따라 다릅니다.

가독성을 위해 여러 구조체를 제안하는 것이 매우 효과적입니다. 그러나 일부 환경에서는 이러한 구조체에 대한 일반적인 조작을 원하며 행렬 * 벡터 연산과 같은 코드가 중복되는 것을 발견 할 수 있습니다. 아무도 벡터를 포팅하지 않았기 때문에 벡터의 풍미에서 특정 연산을 사용할 수 없을 때 실망 할 수 있습니다.

극단적 인 해결책 (우리가 결국에 준)은 get <0> () get <1> () 및 get <2> () 함수를 사용하여 CRTP 템플릿 기반 기본 클래스를 사용하여 요소를 일반적인 방식으로 얻는 것입니다. 그런 다음이 기본 클래스에서 파생 된 직교 또는 극좌표 구조에서 이러한 함수를 정의합니다. 모든 문제를 해결하지만 템플릿 메타 프로그래밍을 배워야하는 다소 어리석은 가격으로 제공됩니다. 그러나 템플릿 메타 프로그래밍이 이미 프로젝트에서 공정한 게임 인 경우 적합 할 수 있습니다.


1
당신의 대답은 매우 흥미 롭습니다. 예를 제공 할 수 있습니까?
전능 한 낙타 Moha

1
내가 한 일의 예를들 수 있습니다. FIR 필터링 극점, 데카르트 및 벡터. 산술 (un) 랩핑, 수학은 상당히 비슷했고 코드는 성능상의 이유로 일부 부분이 복제되었으며 동일한 위치에 템플릿을 사용했습니다. 모든 물건에 다른 이름을 사용했습니다. Cort의 "극단적 솔루션"은 몇 가지 중복을 줄일 수 있었지만 거의 모든 중복을 줄일 수있었습니다.
유진 Ryabtsev

1
나의 첫 번째 반응은 이와 같은 상황이 캐스팅으로 더 잘 해결 될 것이지만 다소 위험하다는 것이 밝혀졌습니다 .
200_success

114

그렇습니다.

구조체의 가치는 단순한 이름으로 데이터를 캡슐화하는 것만이 아닙니다. 값은 의도를 체계화하여 컴파일러가 언젠가 위반하지 않는지 확인하는 데 도움을 줄 수 있다는 것입니다 (예 : 직교 좌표 세트에 대해 극좌표 좌표를 오해).

사람들은 그러한 끔찍한 세부 사항을 기억하는 데는 좋지 않지만 대담하고 독창적 인 계획을 세우는 데 능숙합니다. 컴퓨터는 세부 사항을 잘 이해하고 창의적 계획을 잘 못합니다. 따라서 컴퓨터에 대한 잔소리 세부 정보 유지 관리 작업을 컴퓨터로 전환하여 마음대로 계획을 세우는 것이 좋습니다.


6
+1 컴퓨터를 사용하여 컴퓨터가 잘하는 일을하고 뇌가 자신의 일에 집중하게하는 것에 대한 완벽한 설명.
BrianH

8
"사람들이 읽을 수 있도록, 프로그램은 기계가 실행할 수 있도록 프로그램을 작성해야한다." -Abelson과 Sussman의 "컴퓨터 프로그램의 구조와 해석"에서
hlovdal

18

그렇습니다. 직교와 극좌표는 (그 자리에서) 현명하게 합리적인 좌표 표현 체계이지만, 절대적으로 절대로 혼합해서는 안됩니다 (점 직교가 {1,1} 인 경우 극좌표와 매우 다른 점입니다). }).

필요에 따라, 그것은 또한 같은 방법으로 인터페이스를 좌표 구현하는 가치가있을 수 있습니다 X(), Y(), Displacement()Angle()(또는 가능성 Radius()Theta()에 따라).


직교 좌표와 극좌표에 대한 연산이 다르기 때문에 OP가 해당 구조체에서 클래스를 만드는 것이 훨씬 중요합니다.
Mindwin

1
마지막 단락에 +1하면 이상적인 솔루션입니다. 점은 공간이 객체라는 것입니다. 그 점의 내부 표현은 중요하지 않습니다. 물론 실제 문제 (성능, 반올림 오류)로 인해 문제가 발생할 수 있습니다. 그것은 모두 이것이 무엇을 사용하고 있는지에 달려 있습니다.
BlueRaja-대니 Pflughoeft

또한이 예에서는 변경 될 가능성이 없지만 두 개의 다른 클래스 인 경우 어떤 시점에서 분기 될 수 있다고 말하지 않습니다.
염색 염료

8

결국, 프로그래밍의 목표는 유용한 작업을 수행하기 위해 트랜지스터 비트를 토글하는 것입니다. 그러나 그렇게 낮은 수준에서 생각하면 관리 할 수없는 열풍이 생겨 복잡성을 숨길 수있는 고급 프로그래밍 언어가 있습니다.

이름이 firstand second인 멤버로 구조체를 하나만 만들면 이름이 의미가 없습니다. 본질적으로 메모리 주소로 취급합니다. 그것은 고급 프로그래밍 언어의 목적을 상실합니다.

또한, 그것들이 모두 표현 가능하기 때문에 double그것들을 상호 교환하여 사용할 수 있는 것은 아닙니다. 예를 들어, θ 는 무 차원 각도이며, y 는 길이 단위입니다. 유형은 논리적으로 대체 할 수 없으므로 두 개의 호환되지 않는 구조체 여야합니다.

당신이 경우 정말 메모리 재사용 트릭을 재생해야 - 당신은 거의 확실하게 안 - 당신이 사용할 수있는 union당신의 의도를 명확하게하기 위해 C의 유형입니다.


정답, IMHO
Dean Radcliffe

2

첫째, @ Kilian-foth의 전적으로 건전한 대답에 따라 명시 적으로 두 가지를 모두 갖습니다.

그러나 다음을 추가하고 싶습니다.

질문 : 당신은 실제로 쌍으로 간주 될 때 두 가지에 일반적인 작업이 double있습니까? 이것은 두 가지 모두에 적용되는 작업이 있다는 의미와 다릅니다. 예를 들어 'plot (Coord)'는가 Coord극좌표인지 아니면 직교 좌표 인지를 관리합니다 . 반면에 파일을 유지하는 것은 데이터를 그대로 취급합니다. 실제로 일반 작업을 수행하는 경우 기본 클래스를 정의 std::pair<double, double>하거나 tuple언어에 있는 변환기를 정의 하십시오.

또한, 하나의 접근법은 하나의 좌표 유형을보다 근본적인 것으로 취급하고 다른 하나는 단지 사용자 또는 외부 상호 작용을 지원하는 것으로 취급 할 수있다.

따라서 모든 기본 조작이 코딩되었는지 확인한 Cartesian다음로 변환 Polar을 지원할 수 Cartesian있습니다. 이렇게하면 여러 버전의 여러 작업을 구현하지 않아도됩니다.


1

언어에 따라 가능한 방법은 두 클래스 모두 비슷한 메소드와 조작을 갖을 경우 클래스를 한 번 정의하고 유형 별명을 사용하여 유형의 이름을 다르게 지정하는 것입니다.

또한 클래스가 정확히 동일하면 하나만 유지할 수 있지만 클래스를 변경해야하는 즉시 유형이 이미 사용되었으므로이를 사용하여 코드를 수정할 필요가 없다는 장점이 있습니다. 분명히.

클래스의 사용법에 따라 (다형성이 필요한 경우 등) 또 다른 옵션은 두 가지 새 유형 모두에 대해 공용 상속을 사용하여 둘 다 나타내는 공통 유형과 동일한 공용 인터페이스를 사용하는 것입니다. 이것은 또한 유형의 개별 진화를 허용합니다.


두 클래스의 멤버 이름이 동일하지 않습니다. 실제로 그 이름은 두 계급의 유일한 차이점입니다
전능 한 낙타 Moha

@ Mhd.Tahawi 적절한 이름으로 getter 및 setter를 구현하여 사용중인 클래스는 동일하지만 사용하려는 작업에 적절한 이름을 제공 할 수 있습니다. 좀 더 장황하지만 코드를 적게 복제해야합니다.
Svalorzen

0

이 경우 코드의 오류가 발생하기 쉽기 때문에 동일한 멤버 이름을 갖는 것은 나쁜 생각이라고 생각합니다.

시나리오를 상상해보십시오. 두 개의 직교 점이 있습니다 : pntA와 pntB. 그런 다음 어떤 이유로 든 극좌표로 표시하는 것이 더 좋다고 결정하고 선언과 생성자를 변경하십시오.

이제 모든 작업이 다음과 같은 메소드 호출 인 경우 :

double distance = pntA.distanceFrom(pntB);

그럼 괜찮아 그러나 멤버를 명시 적으로 사용한 경우 어떻게해야합니까? 비교

double leftMargin = abs(pntA.x - pntB.x);
double leftMargin = abs(pntA.first - pntB.first);

첫 번째 경우 코드가 컴파일되지 않습니다. 오류가 즉시 표시되고 수정할 수 있습니다. 그러나 동일한 멤버 이름을 사용하는 경우 오류는 논리적 수준에서만 발생하므로 감지하기가 훨씬 어렵습니다.

객체 지향이 아닌 언어로 작성하면 잘못된 구조체를 함수에 전달하는 것이 더 쉽습니다. 다음 코드를 작성하지 못하게하는 이유는 무엇입니까?

double distance = calculate_distance_polar(cartesianPointA, polarPointB);

반면에 다른 데이터 유형을 사용하면 컴파일 중에 오류를 찾을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.