클래스와 관련이없는 함수를 어디에 두어야합니까?


47

나는 처음에 클래스의 일부로 사용하기 위해 작성한 많은 수학 함수가있는 C ++ 프로젝트를 진행하고 있습니다. 그러나 더 많은 코드를 작성하면서 모든 곳에서 이러한 수학 함수가 필요하다는 것을 깨달았습니다.

가장 좋은 장소는 어디입니까? 내가 이것을 가지고 있다고 가정 해 봅시다.

class A{
    public:
        int math_function1(int);
        ...
}

그리고 다른 수업을 쓸 때 다른 수업에서 사용할 수 없습니다 (또는 방법을 모르겠습니다) math_function1. 또한이 함수 중 일부가 실제로 클래스 A와 관련이 없다는 것을 깨달았습니다. 그들은 처음에있는 것처럼 보였지만 이제는 그것이 어떻게 수학 함수인지 볼 수 있습니다.

이 상황에서 좋은 방법은 무엇입니까? 지금은 새 클래스에 복사하여 붙여 넣었습니다. 최악의 방법이라고 확신합니다.


11
static키워드 에 대해 배웠 습니까?
S.Lott

30
C ++에서 자유 함수는 멤버 함수보다 거의 항상 선호됩니다.
Pubby

4
모든 것이 수업에 있어야한다는 규칙은 없습니다. 적어도 C ++에서는 그렇지 않습니다.
tdammers

2
나는 정적 방법의 무리와 함께 클래스에 네임 스페이스를 원합니다
닉 카일리에게

답변:


70

C ++ 메소드가 아닌 함수는 클래스에 속하지 않으면 클래스에 넣지 말고 전역 또는 다른 네임 스페이스 범위에 두십시오.

namespace special_math_functions //optional
{
    int math_function1(int arg)
    {
         //definition 
    }
}

6
+1 추가 네임 스페이스는 필요하지 않지만 가장 합리적인 솔루션입니다.
Pubby

1
필요하지 않습니다
jk.

27
일부 네임 스페이스는 다른 라이브러리와의 잠재적 인 이름 충돌을 줄이는 데 유용합니다.
Bill Door

11
네임 스페이스를 사용하는 것도 호출이 메서드인지 함수인지 명확하게하기 때문에 좋습니다. ( math_function1(42)현재 클래스의 멤버를 호출 할 수 있습니다 special_math_functions::math_function1(42). 독립 함수를 분명히 호출합니다). 즉 ::math_function(42), 동일한 명확성을 제공합니다.
ipeet

2
네임 스페이스는 필요하지 않지만 금지되지는 않습니다. 따라서 왜이 대답은이라고 말합니다 // optional. 맛에 따라 계절.
user253751

6

프로젝트가 구성되는 방식과 사용중인 디자인 패턴의 종류에 따라 달라집니다. 이는 엄격하게 유틸리티 코드 인 경우 다음 옵션이 있습니다.

  • 모든 것에 객체를 사용할 필요가 없다면 클래스 래퍼없이 파일에 모두 넣는 것과 같은 간단한 작업을 수행 할 수 있습니다. 네임 스페이스는 향후 문제를 방지하기 위해 권장되지만 네임 스페이스를 포함하거나 포함하지 않을 수 있습니다.
  • 관리되는 C ++의 경우 정적 클래스 를 만들어 모두 포함 할 수 있습니다 . 그러나 이것은 실제로 실제 클래스와 동일하게 작동하지 않으며 C ++ 안티 패턴이라는 것을 이해합니다.
  • 관리되는 C ++를 사용하지 않는 경우 정적 함수 를 사용하여 액세스하고 단일 클래스에 모두 포함시킬 수 있습니다. 이것에 의해 적절한 인스턴스화 된 객체를 원하는 다른 기능도 안티 패턴 일 경우 유용합니다.
  • 함수를 포함하는 객체의 인스턴스가 하나만 존재하도록하려면 유틸리티 클래스에 싱글 톤 패턴 을 사용하면 나중에 비 정적 속성에 액세스 할 수 있으므로 약간의 융통성을 제공 할 수 있습니다. 이것은 제한적으로 사용되며 어떤 이유로 객체가 필요한 경우에만 실제로 적용됩니다. 이 방법을 사용하면 이미 이유를 알게 될 것입니다.

첫 번째 옵션이 최선의 선택이 될 것이며 다음 세 가지 옵션은 유용하지 않습니다. 그러나 C # 또는 Java 프로그래머가 C ++ 작업을 수행하거나 클래스 사용이 필수적인 C # 또는 Java 코드 작업을하는 경우 발생할 수 있습니다.


다운 투표를해야하는 이유
rjzii 2019

10
나는 downvoter가 아니지만 아마도 정적 함수 또는 싱글 톤으로 클래스를 조언하고 있기 때문에 무료 함수는 아마도이 경우에는 좋을 것입니다 (그리고 C ++의 많은 것들에 허용되고 유용합니다).
Anton Golov 2019

@AntonGolov-무료 기능은 내가 목록에서 언급 한 첫 번째 것입니다. :) 나머지는 "모든 것이 클래스 여야합니다!" 환경.
rjzii 2019

9
@Rob Z : 그러나 C ++은 "모든 것이 클래스 여야합니다!" 환경.
David Thornley 2012

1
언제부터 순수한 함수를 클래스로 강제하는 것이 OOP입니까? OOP-cargo-cult와 더 비슷합니다.
중복 제거기

1

이미 말했듯이 코드 복사-붙여 넣기는 최악의 코드 재사용 형태입니다. 클래스에 속하지 않거나 여러 시나리오에 사용될 수있는 함수가있는 경우이를 가장 적합한 위치는 도우미 또는 유틸리티 클래스입니다. 인스턴스 데이터를 사용하지 않으면 정적으로 만들 수 있으므로이를 사용하기 위해 유틸리티 클래스의 인스턴스를 만들 필요가 없습니다.

참조 여기 네이티브 C ++에서 정적 멤버 함수에 대한 설명과 여기 ++ 관리 C에서 정적 클래스. 그런 다음 코드를 붙여 넣을 때마다이 유틸리티 클래스를 사용할 수 있습니다.

예를 들어 .NET 에서 클래스의 정적 멤버 Min()와 같은 Max()것이 제공됩니다 .System.Math

모든 함수는 수학 관련하고 당신은 거대한가 otherwiese 할 경우 Math클래스를, 당신은 그것을 더 분해와 같은 클래스가 할 수 있습니다 TrigonometryUtilities, EucledianGeometryUtilities등등을.

다른 옵션은 상기 기능을 필요로하는 클래스의 기본 클래스에 공유 기능을 배치하는 것이다. 문제의 함수가 인스턴스 데이터에서 작동해야하는 경우에는 잘 작동하지만 다중 상속을 피하고 하나의 기본 클래스 만 고수하려는 경우이 방법은 유연성이 떨어집니다. 공유 기능에 액세스 할 수 있습니다.


18
IMHO, 정적 멤버 만있는 유틸리티 클래스는 C ++의 안티 패턴입니다. 네임 스페이스의 동작을 완벽하게 재현하기 위해 클래스를 사용하고 있습니다.
ipeet

유틸리티 클래스를 언급하면 ​​+1입니다. C #과 같은 언어는 모든 것이 클래스에 있어야하므로 다양한 목적을 위해 많은 유틸리티 클래스를 만드는 것이 일반적입니다. 이러한 클래스를 정적으로 구현하면 유틸리티를보다 사용자 친화적으로 만들 수 있으며, 특히 기본 클래스에 하나 또는 두 개의 자손 만 사용할 수있는 코드가 부풀려 질 때 상속으로 인해 발생할 수있는 두통을 피할 수 있습니다. 유틸리티 범위에 대한 의미있는 컨텍스트를 제공하기 위해 다른 언어로 유사한 기술을 적용 할 수 있습니다.
S.Robins 2019

5
@ S.Robins : C ++에서는 이와 같은 것이 필요하지 않으며 네임 스페이스에 넣을 수 있습니다.이 효과는 동일합니다.
DeadMG

0

"도움말 기능"이라는 용어를 명확하게하십시오. 하나의 정의는 작업을 수행하기 위해 항상 사용하는 편의 기능입니다. 이것들은 메인 네임 스페이스에 존재할 수 있고 자체 헤더 등을 가질 수 있습니다. 다른 도우미 함수 정의는 단일 클래스 또는 클래스 패밀리를위한 유틸리티 함수입니다.

// a general helper 
template <class T>
bool isPrinter(T& p){
   return (dynamic_cast<Printer>(p))? true: false;
}

    // specific helper for printers
namespace printer_utils {    
  namespace HP {
     print_alignment_page() { printAlignPage();}
  }

  namespace Xerox {
     print_alignment_page() { Alignment_Page_Print();}
  }

  namespace Canon {
     print_alignment_page() { AlignPage();}
  }

   namespace Kyocera {
     print_alignment_page() { Align(137,4);}
   }

   namespace Panasonic {
      print_alignment_page() { exec(0xFF03); }
   }
} //namespace

이제 isPrinter헤더를 포함한 모든 코드에서 사용할 수 있지만 지시문이 print_alignment_page필요합니다 using namespace printer_utils::Xerox;. 우리는 또한 그것을 참조 할 수 있습니다

Canon::print_alignment_page();

더 명확하게.

C ++ STL에는 std::거의 모든 클래스와 함수를 포함 하는 네임 스페이스가 있지만 코더가 클래스 이름, 함수 이름 등을 쓸 수있게하기 위해 17 가지 이상의 헤더로 범주별로 나눕니다. 자신의.

실제로 using namespace std;헤더 파일이나 내부 행의 첫 번째 행 으로 사용하는 것은 좋지 않습니다 main(). std::5 글자이며, 종종 (특히 사용하는 기능을 하나의 욕구 서문하기 싫은 것 std::cout하고 std::endl!)하지만,이 목적을 제공한다.

새로운 C ++ 11에는 다음과 같은 특수 서비스를위한 하위 네임 스페이스가 있습니다.

std::placeholders,
std::string_literals,
std::chrono,
std::this_thread,
std::regex_constants

사용하기 위해 가져올 수 있습니다.

유용한 기술은 네임 스페이스 구성 입니다. 하나는 특정 .cpp파일에 필요한 네임 스페이스를 보유하고 필요한 네임 스페이스의 using각 항목에 대해 많은 명령문 대신 사용할 네임 스페이스를 정의합니다.

#include <iostream>
#include <string>
#include <vector>

namespace Needed {
  using std::vector;
  using std::string;
  using std::cout;
  using std::endl;
}

int main(int argc, char* argv[])
{
  /*  using namespace std; */
      // would avoid all these individual using clauses,
      // but this way only these are included in the global
      // namespace.

 using namespace Needed;  // pulls in the composition

 vector<string> str_vec;

 string s("Now I have the namespace(s) I need,");

 string t("But not the ones I don't.");

 str_vec.push_back(s);
 str_vec.push_back(t);

 cout << s << "\n" << t << endl;
 // ...

이 기술은 전체에 대한 노출을 제한하고 std:: namespace( 빅! ) 사람들이 가장 자주 쓰는 가장 일반적인 코드 행에 대해 더 깨끗한 코드를 작성할 수 있습니다.


-2

다른 유형의 정수 및 / 또는 부동 소수점에 사용할 수 있도록 템플릿 함수에 넣을 수 있습니다.

template <typename T>
T math_function1(T){
 ..
}

템플릿에 친숙해 지도록 사용자 정의 유형에 관련 연산자를 오버로드하여 예를 들어 거대한 숫자 또는 복소수를 나타내는 깔끔한 사용자 정의 유형을 만들 수 있습니다.

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