문제

기본 매개 변수를 사용하는 클래스 생성자가 있거나 별도의 오버로드 된 생성자를 사용해야합니까? 예를 들어:

// Use this...
class foo  
{
private:
    std::string name_;
    unsigned int age_;
public:
    foo(const std::string& name = "", const unsigned int age = 0) :
        name_(name),
        age_(age)
    {
        ...
    }
};

// Or this?
class foo  
{
private:
    std::string name_;
    unsigned int age_;
public:
    foo() :
    name_(""),
    age_(0)
{
}

foo(const std::string& name, const unsigned int age) :
        name_(name),
        age_(age)
    {
        ...
    }
};

두 버전 모두 작동하는 것 같습니다.

foo f1;
foo f2("Name", 30);

어떤 스타일을 선호하거나 추천하고 이유는 무엇입니까?

도움이 되었습니까?

해결책

확실히 스타일의 문제. 매개 변수가 이해되는 한 기본 매개 변수를 가진 생성자를 선호합니다. 표준의 수업은 그것들을 사용하여 유리하게 말합니다.

조심해야 할 한 가지는 하나의 매개 변수를 제외한 기본값이 있다면 해당 매개 변수 유형에서 클래스를 암시 적으로 변환 할 수 있다는 것입니다. 체크 아웃 이 스레드 더 많은 정보를 위해서.

다른 팁

특히 C ++가 체인 생성자를 허용하지 않기 때문에 기본 인수와 함께 갈 것입니다 (따라서 각 오버로드마다 이니셜 라이저 목록을 복제해야합니다).

즉, 상수가 상환 될 수 있다는 사실을 포함하여 기본 인수가있는 일부 gotchas가 있습니다 (따라서 클래스 이진 인터페이스의 일부가됩니다). 조심해야 할 또 다른 것은 기본 인수를 추가하면 명시적인 다중 연습 생성자를 암시 적 일회성 생성자로 바꿀 수 있다는 것입니다.

class Vehicle {
public:
  Vehicle(int wheels, std::string name = "Mini");
};

Vehicle x = 5;  // this compiles just fine... did you really want it to?

이 논의는 생성자뿐만 아니라 방법과 기능에도 적용됩니다.

기본 매개 변수 사용?

좋은 점은 각 경우에 대한 생성자/방법/함수를 과부하 할 필요가 없다는 것입니다.

// Header
void doSomething(int i = 25) ;

// Source
void doSomething(int i)
{
   // Do something with i
}

나쁜 점은 헤더에서 기본값을 선언해야한다는 것입니다. 따라서 숨겨진 종속성이 있습니다. 상감 기능의 코드를 변경할 때 헤더의 기본값을 변경하면 모든 소스를 다시 컴파일해야합니다. 이 헤더를 사용하여 새 기본값을 사용할 것입니다.

그렇지 않은 경우 소스는 여전히 기존 기본값을 사용합니다.

과부하 된 생성자/방법/기능 사용?

좋은 점은 함수가 손상되지 않으면 하나의 함수가 작동하는 방식을 선택하여 소스의 기본값을 제어한다는 것입니다. 예를 들어:

// Header
void doSomething() ;
void doSomething(int i) ;

// Source

void doSomething()
{
   doSomething(25) ;
}

void doSomething(int i)
{
   // Do something with i
}

문제는 여러 생성자/방법/기능 및 전진을 유지해야한다는 것입니다.

내 경험상, 기본 매개 변수는 당시에 시원 해 보이고 게으름 요소를 행복하게 만들었습니다. 그러나 길을 따라 내려다 보면 클래스를 사용하고 있으며 기본값이 시작될 때 놀랐습니다. 그래서 나는 그것이 좋은 생각이라고 생각하지 않습니다. ; classname :: classname ()을 갖는 것이 더 좋습니다. 그리고 classname :: init (Arglist). 그 유지 관리 에지만을 위해.

답변은 과부하보다는 생성자에게 기본 인수가 바람직하다는 이유를 제시합니다. 나는 단지 c ++ -0x를 허용 할 것입니다. 대표단 한 생성자에서 다른 생성자로, 기본값이 필요하지 않습니다.

두 가지 접근 방식이 작동합니다. 그러나 옵션 매개 변수의 긴 목록이있는 경우 기본 생성자를 만들고 설정 함수가 이에 대한 참조를 반환하도록하십시오. 그런 다음 정착기를 체인합니다.

class Thingy2
{
public:
    enum Color{red,gree,blue};
    Thingy2();

    Thingy2 & color(Color);
    Color color()const;

    Thingy2 & length(double);
    double length()const;
    Thingy2 & width(double);
    double width()const;
    Thingy2 & height(double);
    double height()const;

    Thingy2 & rotationX(double);
    double rotationX()const;
    Thingy2 & rotatationY(double);
    double rotatationY()const;
    Thingy2 & rotationZ(double);
    double rotationZ()const;
}

main()
{
    // gets default rotations
    Thingy2 * foo=new Thingy2().color(ret)
        .length(1).width(4).height(9)
    // gets default color and sizes
    Thingy2 * bar=new Thingy2()
        .rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
    // everything specified.
    Thingy2 * thing=new Thingy2().color(ret)
        .length(1).width(4).height(9)
        .rotationX(0.0).rotationY(PI),rotationZ(0.5*PI);
}

이제 객체를 구성 할 때 재정의 할 속성을 선택할 수 있으며 설정 한 속성이 명시 적으로 명명 될 수 있습니다. 훨씬 더 읽기 쉬운 :)

또한 더 이상 생성자에 대한 인수의 순서를 기억할 필요가 없습니다.

고려해야 할 점은 클래스가 배열에서 사용할 수 있는지 여부입니다.

foo bar[400];

이 시나리오에서는 기본 매개 변수를 사용하는 데 이점이 없습니다.

이것은 확실히 작동하지 않을 것입니다.

foo bar("david", 34)[400]; // NOPE

인수가있는 생성자를 만드는 것이 나쁘다면 (많은 사람들이 논쟁하는 것처럼) 기본 인수로 만드는 것이 더 나쁩니다. 나는 최근에 당신의 ctor 논리가 가능한 한 최소화하십시오. CTOR에서 오류 처리를 어떻게 처리합니까? 누군가가 말이되지 않는 논쟁을 통과해야합니까? 모든 발신자가 시도 블록 내부에 "새로운"통화를 감싸거나 일부 "이니셜 화"멤버 변수를 설정하지 않는 한 예외는 예외를 던질 수 있습니다.

따라서 인수가 객체의 초기화 단계로 전달되는지 확인하는 유일한 방법은 리턴 코드를 확인할 수있는 별도의 초기화 () 메소드를 설정하는 것입니다.

기본 인수의 사용은 두 가지 이유로 나쁘다. 우선, CTOR에 또 다른 인수를 추가하려면 처음에 그것을 넣고 전체 API를 변경하는 것입니다. 또한 대부분의 프로그래머는 실제로 사용되는 방식으로 API를 파악하는 데 익숙합니다. 특히 공식 문서가 존재하지 않는 조직 내부에서 사용되는 비공개 API의 경우에 해당됩니다. 다른 프로그래머가 대부분의 통화에 인수가 포함되어 있지 않다는 것을 알면, 기본 인수가 그들에게 부과되는 기본 동작을 행복하게 알지 못하면서 동일하게 수행 할 것입니다.

또한, 그것은 주목할 가치가 있습니다 Google C ++ 스타일 가이드 CTOR의 주장을 피하고 (절대적으로 필요한 경우가 아니라면) 함수 또는 방법에 대한 기본 인수.

이런 이유로 기본 매개 변수와 함께 이동합니다. 예제는 CTOR 매개 변수가 멤버 변수에 직접 해당한다고 가정합니다. 그러나 그렇지 않은 경우 객체가 초기화되기 전에 매개 변수를 처리해야합니다. 하나의 공통된 CTOR를 갖는 것이 가장 좋은 방법입니다.

기본 매개 변수로 나를 괴롭히는 한 가지는 마지막 매개 변수를 지정할 수 없지만 첫 번째 매개 변수의 기본 값을 사용한다는 것입니다. 예를 들어, 코드에서는 이름이없는 Foo를 만들 수 없습니다. 때로는 이것이 의미가 있지만 정말 어색 할 수도 있습니다.

제 생각에는 경험의 규칙이 없습니다. Personaly, 나는 마지막 인수만이 기본값이 필요한 경우를 제외하고 여러 과부하 된 생성자 (또는 방법)를 사용하는 경향이 있습니다.

대부분 개인적인 선택. 그러나 과부하는 기본 매개 변수를 수행 할 수 있지만 ~ 아니다 그 반대도 마찬가지입니다.

예시:

오버로드를 사용하여 (int x, foo & a)와 a (int x)를 쓸 수 있지만 기본 매개 변수를 사용하여 a (int x, foo & = null)를 작성할 수는 없습니다.

일반적인 규칙은 의미가있는 모든 것을 사용하고 코드를 더 읽기 쉽게 만드는 것입니다.

스타일의 문제이지만 Matt가 말했듯이, 의도하지 않은 자동 변환을 피하기 위해 암시 적 변환을 '명시 적'으로 허용하는 기본 인수가있는 생성자를 표시하는 것을 고려하십시오. 요구 사항이 아니며 (암시 적으로 변환하려는 래퍼 클래스를 만드는 경우에는 바람직하지 않을 수 있지만) 오류를 방지 할 수 있습니다.

반복 코드를 싫어하기 때문에 개인적으로 적절한 경우 기본값을 좋아합니다. ymmv.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top