매개 변수가없는 생성자를 만들 때 기본 매개 변수없는 생성자가 사라지는 이유


161

C #, C ++ 및 Java에서 매개 변수를 사용하는 생성자를 만들면 기본 매개 변수가없는 생성자가 사라집니다. 나는 항상이 사실을 받아 들였지만 이제는 왜 그런지 궁금해하기 시작했습니다.

이 행동의 이유는 무엇입니까? "자신의 생성자를 만든 경우이 암시 적 생성자를 원하지 않을 "이라고 말하는 것이 "안전 측정 / 추측" 일 뿐입니 까? 또는 생성자를 직접 만든 후에는 컴파일러에서 컴파일러를 추가 할 수없는 기술적 이유가 있습니까?


7
이 동작이있는 언어 목록에 C ++을 추가 할 수 있습니다.
Henk Holterman

18
그리고 C ++에서는 이제 Foo() = default;기본 설정을 되 찾으라고 말할 수 있습니다 .
MSalters

1
매개 변수가있는 생성자가 모든 매개 변수에 대한 기본 인수를 가질 수있는 경우 내장 매개 변수가없는 생성자와 충돌하므로 직접 만들 때이를 삭제해야합니다.
Morwenn

3
첫 번째 컴파일러의 창시자 사이에서 기본 생성자 요구 사항과 영감을 얻은 열띤 토론을 나누기 위해이 토론에 참석한다고 상상해보십시오.
kingdango

7
@HenkHolterman C ++ 은이 동작의 또 다른 것이 아니라 작성자이며 C ++ 의 디자인 및 진화 에서 Stroustrup이 논의하고 업데이트 된 답변에 요약 된 것처럼 C 호환성을 허용 합니다.
Jon Hanna

답변:


219

직접 추가 한 경우 컴파일러에서 생성자를 추가 할 수있는 이유는 없습니다. 컴파일러는 원하는대로 수행 할 수 있습니다! 그러나 가장 의미가있는 것을 살펴 봐야합니다.

  • 비 정적 클래스에 대한 생성자를 정의 하지 않은 경우 해당 클래스를 인스턴스화 할 수 있기를 원할 것입니다. 이를 허용하기 위해 컴파일러 매개 변수가없는 생성자를 추가 해야합니다 . 즉, 코드를 작성하기 위해 빈 생성자를 내 코드에 포함시킬 필요가 없습니다.
  • 내 자신의 생성자, 특히 매개 변수가있는 생성자를 정의했다면 클래스를 만들 때 실행 해야하는 내 자신의 논리가있을 가능성이 큽니다. 컴파일러 가이 경우 빈 매개 변수가없는 생성자를 만들면 누군가 내가 작성한 논리 를 건너 뛸 수 있으므로 여러 가지 방법으로 코드가 손상 될 수 있습니다. 이 경우 기본 빈 생성자를 원하면 명시 적으로 말해야합니다.

따라서 각 경우에 현재 컴파일러의 동작 이 코드의 의도 를 보존하는 데 가장 적합하다는 것을 알 수 있습니다 .


2
나는 당신의 나머지 답변이 첫 문장이 잘못되었다는 것을 거의 증명합니다.
Konrad Rudolph

76
첫 번째 문장 인 @KonradRudolph는 컴파일러 가이 시나리오에서 생성자를 추가 할 수 있다고 말합니다. 나머지 답변은 왜 그렇지 않은지 설명합니다 (질문에 지정된 언어의 경우)
JohnL

1
음 ... 아니. 우리가 처음부터 OO 언어를 설계했다면, 생성자가 없다는 것의 가장 명백한 의미는 "클래스의 불변성을 보장하는 생성자를 추가하는 것을 소홀히했다"는 것이며 컴파일 오류를 일으킬 것입니다.
존 한나

70

언어 이런 식으로 설계되어야 하는 기술적 이유는 없습니다 .

내가 볼 수있는 다소 현실적인 옵션이 있습니다.

  1. 기본 생성자가 전혀 없습니다
  2. 현재 시나리오
  3. 기본적으로 항상 기본 생성자를 제공하지만 명시 적으로 억제되도록 허용
  4. 억제 하지 않고 항상 기본 생성자 제공

옵션 1은 더 I 코드가 덜 자주는 점에서 다소 매력적이다 정말 매개 변수없는 생성자를 원한다. 언젠가 나는 기본 생성자를 사용하여 실제로 얼마나 자주 끝나는 지 계산해야합니다 ...

옵션 2 괜찮습니다.

옵션 3은 나머지 언어에 대해 Java와 C #의 흐름에 반합니다. Java에서 기본적으로 사적인 것들을 명시 적으로 만드는 것을 제외하고는 명시 적으로 "제거"하는 것은 없습니다.

옵션 4 끔찍 - 당신은 절대적으로 특정 매개 변수와 건설을 강제 할 수 있어야합니다. 무엇을 new FileStream()의미할까요?

그러니까 기본적으로, 경우에 당신은 기본 생성자를 제공하는 것이 전혀 의미가 있다는 전제를 받아, 나는 그것이 바로 당신이 당신의 자신의 생성자를 제공하기로 억제하는 많은 이해 믿습니다.


1
나는 옵션 3을 좋아합니다. 무언가를 쓸 때 두 유형의 생성자를 모두 필요로하고 매개 변수를 가진 생성자를 더 자주 사용해야하기 때문입니다. 그래서 나는 하루에 한 번 매개 변수가없는 생성자를 비공개로 만들고 하루에 10 번 매개 변수가없는 생성자를 작성합니다. 그러나 아마 나만으로, 나는 많은 seriaziable 클래스를 작성하고 있습니다 ...
Petr Mensik

8
@PetrMensik : 매개 변수가없는 생성자가 실제로 아무 것도 할 필요가없는 경우 "명시적인 제거"문보다 훨씬 많은 코드를 사용하지 않는 단일 라이너입니다.
Jon Skeet

2
@PetrMensik : 죄송합니다. 제 실수입니다. 그것은 내 경험과는 정반대입니다. 그리고 자동으로 무언가를 포함하는 것이 더 위험한 옵션 이라고 주장 합니다. 우연히 그것을 배제하지 않으면 결국 불변을 망칠 수 있습니다.
Jon Skeet

2
# 4는 C # struct의 경우에 해당합니다 .
Jay Bazuzi

4
이해하기 쉽기 때문에 옵션 1이 마음에 듭니다. 코드에서 볼 수없는 "마법의"생성자가 없습니다. 옵션 1을 사용하면 비 정적 클래스에 인스턴스 생성자가없는 경우 컴파일러는 경고를 발생시켜야합니다. 방법 : "클래스 <TYPE>에 대한 인스턴스 생성자가 없습니다. 클래스를 정적으로 선언 하시겠습니까?"
Jeppe Stig Nielsen

19

편집하다. 사실, 첫 번째 답변에서 내가 말하는 것은 유효하지만 이것이 진정한 이유입니다. :

처음에는 C가있었습니다. C는 객체 지향적이지 않습니다 (OO 접근 방식을 취할 수는 있지만 도움이되지 않습니다).

그런 다음 C With Classes가 있었고 나중에 C ++로 이름이 바뀌 었습니다. C ++는 객체 지향적이므로 캡슐화를 장려하고 구성시 및 메소드 시작 및 종료시 객체가 유효한 상태에있게합니다.

이것과 관련된 자연스러운 일은 클래스가 항상 유효한 상태에서 시작되도록 생성자가 있어야한다는 것입니다. 생성자가 이것을 보장하기 위해 아무것도 할 필요가 없다면 빈 생성자는이 사실을 문서화합니다 .

그러나 C ++의 목표는 가능한 한 모든 유효한 C 프로그램도 유효한 C ++ 프로그램이었습니다 (더 이상 목표가 유효하지 않으며 C의 C ++ 로의 진화는 더 이상 보유하지 않음을 의미합니다). ).

이 중 하나 개 효과는 간 기능의 중복이었다 structclass. 전자는 C 방식으로 작업을 수행하고 (기본적으로 모든 것이 공개됨) 후자는 좋은 OO 방식으로 작업을 수행합니다 (기본적으로 비공개 인 경우 개발자는 원하는 것을 공개적으로 공개합니다).

다른 하나는 C struct에 생성자가 없기 때문에 생성자를 가질 수없는 C가 C ++에서 유효하기 위해서는 C ++에서이를 보는 의미가 있어야한다는 것입니다. 따라서 생성자가없는 것은 변형을 적극적으로 보장하는 OO 관행에 위배되지만 C ++은 빈 본문이있는 것처럼 작동하는 기본 매개 변수가없는 생성자가 있음을 의미했습니다.

모든 C structs는 이제 유효한 C ++이었습니다 structs. (이것은 classes마치 매개 변수가없는 단일 생성자가있는 것처럼 외부에서 모든 것을 처리하는 C ++ 과 동일하다는 것을 의미 합니다.

그러나 생성자를 classor struct에 넣은 경우 C 방식이 아닌 C ++ / OO 방식으로 작업을 수행했으며 기본 생성자가 필요하지 않았습니다.

간결한 역할을 했으므로 호환성이 불가능한 경우에도 사람들은 계속 사용했습니다 (C가 아닌 다른 C ++ 기능을 사용했습니다).

따라서 Java가 여러 가지 방법으로 C ++을 기반으로하고 나중에 C # (여러 가지 방법으로 C ++ 및 Java를 기반으로)을 도입했을 때, 이미 코더가 익숙한 것처럼이 접근법을 유지했습니다.

Stroustrup은 C ++ 프로그래밍 언어로 이에 대해 썼으며 C ++ 의 디자인과 진화 에서 언어의“왜”에 더 중점을 두었습니다 .

=== 원래 답변 ===

이것이 일어나지 않았다고 가정 해 봅시다.

클래스가없는 상태를 의미있는 상태로 만들 수 없기 때문에 매개 변수가없는 생성자를 원하지 않는다고 가정 해 봅시다. 실제로 이것은 structC #에서 발생할 수있는 일입니다 (그러나 C #에서 0을 null struct로 의미있게 사용할 수 없다면 공개적으로 볼 수없는 최적화를 사용하는 것이 가장 좋습니다. struct) 를 사용하여 디자인 결함 .

클래스가 불변을 보호 할 수있게하려면 특별한 removeDefaultConstructor키워드 가 필요 합니다. 최소한 호출 코드가 기본값을 호출하지 않도록 개인 매개 변수없는 생성자를 만들어야합니다.

언어를 좀 더 복잡하게 만듭니다. 하지 않는 것이 좋습니다.

대체로 생성자를 추가하는 것으로 생각하지 않는 것이 가장 좋습니다. 아무것도하지 않는 매개 변수가없는 생성자를 추가하기 위해 생성자가없는 구문 설탕으로 생각하는 것이 좋습니다.


1
그리고 다시, 나는 누군가가 이것이 투표하기에 나쁜 대답이라고 생각하지만, 나 또는 다른 사람을 깨우칠 수는 없다고 생각합니다. 유용 할 수 있습니다.
존 한나

내 대답도 마찬가지입니다. 글쎄, 여기에 잘못된 것이 보이지 않으므로 나에게서 +1합니다.
Botz3000

@ Botz3000 점수에 신경 쓰지 않지만 비평을 받았다면 오히려 읽습니다. 아직도, 그것은 위에 추가 할 무언가를 생각하게했습니다.
Jon Hanna

1
그리고 다시 설명없이 다운 투표로. 설명이 필요하지 않은 것이 분명하지 않다면, 내가 바보라고 가정하고 어쨌든 설명을 부탁드립니다.
Jon Hanna

1
@jogojapan 나도 전문가는 아니지만 결정을 내리는 사람은 그것에 대해 썼기 때문에 그렇게 할 필요는 없습니다. 덧붙여서, 그것은 매우 흥미로운 책입니다. 한 사람의 연설과 같은 재미있는 내용으로 연설 전에 바로 새로운 기능을 제안하기 전에 신장을 기증해야한다고 말하는 저수준 기술과 디자인 결정에 대한 내용은 거의 없습니다. 템플릿과 예외를 모두 소개합니다.
존 한나

13

객체 생성을 제어하기 위해 직접 작업을 수행하지 않으면 기본 매개 변수가없는 생성자가 추가됩니다. 제어 할 단일 생성자를 만든 후에는 컴파일러가 "백 오프"하여 모든 권한을 갖습니다.

이 방법이 아닌 경우 매개 변수가있는 생성자를 통해서만 객체를 생성 할 수있게하려면 기본 생성자를 비활성화하는 명시적인 방법이 필요합니다.


실제로 그 옵션이 있습니다. 매개 변수가없는 생성자를 비공개로 만듭니다.
mw_21

5
동일하지 않습니다. 정적 메소드를 포함한 클래스의 모든 메소드가이를 호출 할 수 있습니다. 나는 완전히 존재하지 않는 것을 선호합니다.
Anders Abel

3

컴파일러의 편의 기능입니다. 매개 변수를 사용하여 생성자를 정의하지만 매개 변수없는 생성자를 정의하지 않으면 매개 변수없는 생성자를 허용하지 않을 가능성이 훨씬 높습니다.

이것은 빈 생성자로 초기화하는 것이 의미가없는 많은 객체의 경우입니다.

그렇지 않으면 제한하려는 각 클래스에 대해 개인 매개 변수없는 생성자를 선언해야합니다.

제 생각에는 매개 변수가 필요한 클래스의 매개 변수가없는 생성자를 허용하는 것은 좋은 스타일이 아닙니다.


3

나는 다른 질문을해야한다고 생각합니다. 다른 생성자를 정의하지 않은 경우 기본 생성자를 선언 해야하는 이유는 무엇입니까?

비 정적 클래스에는 생성자가 필수입니다.
따라서 생성자를 정의하지 않은 경우 생성 된 기본 생성자는 C # 컴파일러의 편리한 기능이며 생성자가 없으면 클래스가 유효하지 않습니다. 따라서 아무것도하지 않는 생성자를 암시 적으로 생성하는 데 아무런 문제가 없습니다. 빈 생성자를 사용하는 것보다 확실히 더 깨끗해 보입니다.

이미 생성자를 정의한 경우 클래스가 유효하므로 컴파일러에서 기본 생성자를 원한다고 가정해야하는 이유는 무엇입니까? 원하지 않으면 어떻게합니까? 컴파일러에게 기본 생성자를 생성하지 않도록 지시하는 속성을 구현 하시겠습니까? 나는 그것이 좋은 생각이라고 생각하지 않습니다.


1

기본 생성자는 클래스에 생성자가없는 경우에만 생성 할 수 있습니다. 컴파일러는이를 백업 메커니즘으로 만 제공하도록 작성되었습니다.

매개 변수화 된 생성자가있는 경우 기본 생성자를 사용하여 오브젝트를 작성하지 않을 수 있습니다. 컴파일러가 기본 생성자를 제공했다면 인수없이 객체가 생성되지 않도록하기 위해 인수없는 생성자를 작성하고 비공개로 만들어야했습니다.

또한 기본 생성자를 비활성화하거나 '비공개'하여 잊어 버릴 수있는 잠재적 인 기능 오류가 발생할 가능성이 높아집니다.

이제 객체를 기본 방식으로 만들거나 매개 변수를 전달하여 인수가없는 생성자를 명시 적으로 정의해야합니다. 이것은 강력하게 확인되고 컴파일러는 달리 불평하여 허점을 보장하지 않습니다.


1

전제

이 동작은 클래스에 기본 public 매개 변수없는 생성자가있는 결정 의 자연스러운 확장으로 볼 수 있습니다 . 요청 된 질문에 근거하여, 우리는이 결정을 전제로 삼고이 경우에 질문하지 않는다고 가정합니다.

기본 생성자를 제거하는 방법

기본 공용 매개 변수없는 생성자를 제거 할 수있는 방법이 있어야합니다. 이 제거는 다음과 같은 방법으로 수행 할 수 있습니다.

  1. 비공개 매개 변수가없는 생성자 선언
  2. 매개 변수가있는 생성자가 선언되면 매개 변수없는 생성자를 자동으로 제거
  3. 매개 변수가없는 생성자를 제거하도록 컴파일러에 표시하는 일부 키워드 / 속성 (배제하기 쉬운 어색함)

최상의 솔루션 선택

이제 우리는 스스로에게 묻습니다. 매개 변수가없는 생성자가 없다면 무엇으로 대체해야합니까? 그리고 어떤 유형의 시나리오에서 기본 공개 매개 변수없는 생성자를 제거하고 싶습니까?

물건이 제자리에 떨어지기 시작합니다. 먼저 매개 변수가있는 생성자 또는 비 공용 생성자로 대체되어야합니다. 둘째, 매개 변수가없는 생성자를 원하지 않는 시나리오는 다음과 같습니다.

  1. 우리는 클래스가 전혀 인스턴스화되는 것을 원하지 않거나 생성자의 가시성을 제어하려고합니다 : 비 공용 생성자를 선언하십시오
  2. 구성시 매개 변수를 제공하려고합니다. 매개 변수를 사용하여 생성자 선언

결론

C #, C ++ 및 Java가 기본 공용 매개 변수없는 생성자를 제거 할 수있는 두 가지 방법이 있습니다.


명확하게 구조화되고 따르기 쉬운 +1 그러나 위의 (3.)에 관해서 : 생성자 제거를위한 특별한 키워드가 그렇게 어색한 아이디어라고 생각하지 않으며 실제로 C ++ 11 = delete이이 목적으로 도입 되었습니다.
jogojapan

1

나는 이것이 컴파일러에 의해 처리된다고 생각합니다. .net어셈블리 를 열면 ILDASM코드에없는 경우에도 기본 생성자가 표시됩니다. 매개 변수화 된 생성자를 정의하면 기본 생성자가 보이지 않습니다.

실제로 클래스를 정의 할 때 (비 정적) 컴파일러는 인스턴스를 생성 할 것이라고 생각하는이 기능을 제공합니다. 그리고 특정 작업을 수행하려면 자신의 생성자가 있어야합니다.


0

생성자를 정의하지 않으면 컴파일러가 인수를 사용하지 않는 생성자를 자동으로 생성하기 때문입니다. 생성자에서 더 많은 것을 원할 때 그것을 무시합니다. 이것은 과부하 기능이 아닙니다. 이제 컴파일러가 보는 유일한 생성자는 인수를 취하는 생성자입니다. 이 문제를 해결하기 위해 생성자가 값없이 전달되면 기본값을 전달할 수 있습니다.


0

클래스에는 생성자가 필요합니다. 필수 요건입니다.

  • 생성하지 않으면 매개 변수가없는 생성자가 자동으로 제공됩니다.
  • 매개 변수가없는 생성자를 원하지 않으면 직접 생성해야합니다.
  • 매개 변수가없는 생성자와 매개 변수 기반 생성자가 모두 필요한 경우 수동으로 추가 할 수 있습니다.

다른 질문에 답할 것입니다. 왜 항상 기본 매개 변수없는 생성자를 원합니까? 이것이 바람직하지 않은 경우가 있으므로 개발자는 필요에 따라 추가하거나 제거 할 수 있습니다.

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