54

그래서 변환 연산자와 생성자에 대한 몇 가지 질문을 통해 저에게 상호 작용에 대해 생각해 보았습니다. 즉 '모호한'호출이있을 때입니다. 다음 코드를 고려하십시오.변환 생성자 대 변환 연산자 : 우선 순위

class A; 

class B { 
     public: 
     B(){} 

     B(const A&) //conversion constructor 
     { 
       cout << "called B's conversion constructor" << endl; 
     } 
}; 

class A { 
     public: 
     operator B() //conversion operator 
     { 
       cout << "called A's conversion operator" << endl; 
       return B(); 
     } 
}; 

int main() 
{ 
    B b = A(); //what should be called here? apparently, A::operator B() 
    return 0; 
} 

위의 코드는 "A의 변환 연산자"라고 표시합니다. 즉, 변환 연산자가 생성자와 달리 호출됩니다. operator B() 코드를 A에서 제거/주석 처리하면 컴파일러는 대신 코드를 변경하지 않고 생성자를 사용하여 기꺼이 전환합니다.

내 질문은 :

  1. 컴파일러는 모호한 전화로 B b = A();을 고려하지 않기 때문에

    , 여기에 직장에서 우선 순위의 몇 가지 유형이 있어야합니다. 이 우선 순위는 정확히 어디에 설정되어 있습니까? (C++ 표준의 참조/인용문은 인정 될 것입니다.)
  2. 객체 지향 철학적 관점에서 보면 코드가 어떻게 동작해야합니까? A 개체가 B 개체 인 A 또는 B이되는 방법에 대해 더 알고있는 사람은 누구입니까? C++에 따르면 대답은 A입니다. 객체 지향적 인 실습에 이것이 있어야한다고 제안하는 것이 있습니까? 개인적으로 나에게도 의미가있을 것입니다. 그래서 선택이 어떻게 이루어 졌는지 알고 싶습니다.

사전

당신은 초기화를 복사 할
+0

당신이 주석 라인 "//이 생성자를 복사는"그것은 생성자, 복사 생성자되지 않습니다 : 다음 코드는 여전히 B의 생성자를 호출하기 때문에 아마도 그것은, 임시직에 대한 몇 가지 특별한 행동을 가지고있다. –

+0

네가 맞아, 나는 그 용어를 오용 했어. 나는 그것을 편집했다. – GRB

답변

42

감사하고, 변환 순서에서 변환을 수행하는 것으로 간주됩니다 후보 함수는 변환 함수 및 변환 생성자입니다. 이들은 귀하의 경우입니다

B(const A&) 
operator B() 

이제 귀하가 신고하는 방법입니다. 과부하 해결은 그로부터 추상화되어 각 후보를 호출 인수에 해당하는 매개 변수 목록으로 변환합니다. 매개 변수는

B(const A&) 
B(A&) 

입니다. 두 번째 이유는 변환 함수가 멤버 함수이기 때문입니다. A&은 후보가 구성원 함수 일 때 생성되는 암시 적 개체 매개 변수입니다. 이제 인자의 타입은 A입니다. 암시 적 객체 매개 변수를 바인딩 할 때 비 const 참조 에 바인딩 할 수 있습니다. 그래서, 또 다른 규칙은 매개 변수가 참조 인 두 가지 실행 가능 함수가있을 때 이 가장 적은 후보가 const 자격을 얻는다는 것입니다. 그것이 귀하의 전환 기능이 승리하는 이유입니다. operator B을 const 멤버 함수로 만들어보십시오. 모호한 점을 알게 될 것입니다.

객체 지향 철학적 관점에서 보면 코드가 어떻게 동작해야합니까? A 객체가 B 객체 (A 또는 B)가되어야하는 방법에 대해 누가 더 알고 있습니까? C++에 따르면 대답은 A입니다. 객체 지향적 인 실습에 이것이 있어야한다고 제안하는 것이 있습니까? 개인적으로 나에게도 의미가있을 것입니다. 그래서 선택이 어떻게 이루어 졌는지 알고 싶습니다. 당신이 변환 기능을 const 멤버 함수를 만들 경우 공식적으로

은 다음 GCC는 생성자 선택합니다 (그래서 GCC는 B 그것으로 더 많은 비즈니스를 가지고 있다고 생각하는 것입니까?). Pedantic 모드 ( -pedantic)로 전환하여 진단을 받도록하십시오.


Standardese 그렇지 8.5/14

(즉, 나머지 복사본 초기화 경우에), 대상 유형에 소스 유형 변환 또는 수있는 사용자 정의 변환 시퀀스 (전환 함수가 사용 된 경우)의 파생 클래스는 13.3.1.4에서 설명한대로 열거되고 가장 좋은 것은 과부하 해결 (13.3)을 통해 선택됩니다.

그리고 13.3.1.4

과부하 해상도가 호출 될 사용자 정의 변환을 선택하는 데 사용됩니다.

  • 변환 생성자 T의 (12.3.1)이 후보 함수이다 : 이하 「CV1의 T "은 개체의 타입 T 클래스 타입으로 초기화되는 것으로 가정하면, 후보 함수가 선택된다.
  • 이니셜 라이저 표현식의 유형이 "cv S"클래스 유형 인 경우 S와 그 기본 클래스의 변환 함수가 고려됩니다. S 내에 숨겨져 있지 않고 cv-unqualified 버전이 T와 동일한 유형이거나 그 파생 클래스 인 유형을 산출하는 것은 후보 함수입니다. "X에 대한 참조"를 반환하는 변환 함수는 X 유형의 lvalue를 반환하므로 후보 함수를 선택하는 과정에서 X를 산출하는 것으로 간주됩니다.

두 경우 모두 인수 목록에는 이니셜 라이저 식인 인수가 하나 있습니다. [주 :이 인수는 생성자의 첫 번째 매개 변수와 변환 함수의 암시 적 객체 매개 변수와 비교됩니다. ]

그리고 13.3.3.2/3

  • 표준 변환 시퀀스 S1은 [...] S1과 S2는 기준 바인딩 (8.5.3)의 경우 표준 변환 시퀀스 S2보다 나은 변환 시퀀스이며 참조가 참조하는 형태는 최상 정도의 cv 수식자를 제외 해 같은 형태이며, S2에 의해 초기화 된 참조가 참조하는 형태는 S1에 의해 초기화 된 참조가 참조하는 형태보다 cv 수식됩니다.
+1

아, 그래서 내 문제는 생성자와 연산자 사이의 우선 순위가 아니라 각각의 'const'-ness입니다. 당신이 옳았다. 연산자 B()를 연산자 B() const로 변경하면 모호한 오류가 발생했다. – GRB

+1

내가 예전처럼 다른 "대답"에 동일한 "분석"을 넣은 것은 얼마나 우연한 일입니까? http://stackoverflow.com/questions/1051379/is-there-a-difference-in-c-between-copy- 초기화 및 할당 초기화/1051468 # 1051468 xD –

+0

답의 첫 번째 문장에 대한 빠른 질문입니다. '당신은 복사 초기화를합니다 ...'. 어디에서나 사본이 생성되는 것을 보지 못합니다. 즉, 다른 A (B라는 다른 B의 B도 아닙니다)에서 A가 생성되지 않습니다. 따라서 문자 그대로 사본을 의미하지는 않습니다. 초기화'라기보다는 '할당 초기화'라인을 따라 무엇인가? 감사! –

3

MSVS2008은 생성자의 선택에 대한 자신의 의견을 것 같다 : 그것은 A의 연산자의 const와 관계없이 B에서 복사 생성자를 호출합니다. 따라서 표준이 올바른 동작을 지정하는 경우에도 여기에서주의하십시오.

MSVS는 변환 연산자 이전에 적합한 생성자를 검색했지만 B의 생성자에서 const 단어를 제거하면 A의 연산자 B()가 시작된다는 것을 알았습니다.

A a; 

B b = a;