기능을 호출 할 때 잘못된 인수 변환이 선호됩니다
-
20-08-2019 - |
문제
나는 MS Visual C ++ 6.0에 따라 프로그램을 작성하고 있습니다 (예, 고대라는 것을 알고 있습니다. 업그레이드를 위해 할 수있는 일은 없습니다). 나는 정말 이상하다고 생각하는 행동을보고 있습니다. 다음과 같이 정의 된 두 개의 생성자가있는 클래스가 있습니다.
class MyClass
{
public:
explicit MyClass(bool bAbsolute = true, bool bLocation = false) : m_bAbsolute(bAbsolute), m_bLocation(bLocation) { ; }
MyClass(const RWCString& strPath, bool bLocation = false);
private:
bool m_bAbsolute;
bool m_bLocation;
};
이 클래스의 인스턴스를이 구문으로 인스턴스화 할 때 : MyClass("blah")
, 첫 번째 생성자라고합니다. 보시다시피, 나는 추가했다 explicit
그것을하지 않을 것이라는 희망으로 그것에 대한 키워드 ... 주사위는 없습니다. 전환을 선호하는 것으로 보입니다 const char *
에게 bool
전환을 통해 RWCString
, 여기에는 복사 생성자가 있습니다 const char *
. 왜 그렇게합니까? 나는 이와 같은 두 가지 가능한 선택이 주어지면 그것이 모호하다고 말할 것입니다. 이 작업을 수행하지 못하게하려면 어떻게해야합니까? 가능하다면, 나는 명시 적으로 캐스팅하지 않아도됩니다. strPath
an에 대한 논쟁 RWCString
, 그것은 리터럴과 함께 많이 사용될 것이므로 많은 추가 타이핑입니다 (정말 쉬운 실수).
해결책
생성자가 암시 적 변환의 일부가 아니라 수신자에 불과하기 때문에 명시 적은 여기에서 도움이되지 않습니다.
선호하는 변환 순서를 제어 할 수있는 방법은 없지만 Const Char*를 취한 두 번째 생성자를 추가 할 수 있습니다. 예 :
class MyClass
{
public:
MyClass(bool bAbsolute = true, bool bLocation = false);
MyClass(const RWCString& strPath, bool bLocation = false);
MyClass(const char* strPath, bool bLocation = false);
private:
bool m_bAbsolute;
bool m_bLocation;
};
다른 팁
Andrew Grant는 해결책을 제공했습니다. 말하고 싶어요 왜 시도한 방식으로 작동하지 않습니다. 인수에 대한 두 가지 실행 가능한 기능이 있다면, 가장 인수와 일치하는 기능을 가장 많이 부릅니다. 두 번째는 사용자 정의 변환이 필요하지만 첫 번째는 표준 변환 만 필요합니다. 그렇기 때문에 컴파일러가 첫 번째를 두 번째로 선호하는 이유입니다.
당신이 계속 캐스팅하고 싶지 않다면, 당신은 const char*를 취하는 다른 ctor를 만들어야 할 것 같습니다.
그것이 내가이 상황에서 아마도 할 것입니다.
(왜 당신이 대부분의 사용을 통과하지 못하는 유형의 ctor를 만들고 있는지 잘 모르겠습니다.)
편집하다:
내가 내 입력하는 동안 다른 사람이 이미 게시 한 것을 봅니다.
왜 끈과 부울에 대한 언급을 혼동 해야하는지 잘 모르시겠습니까? 나는 bool과 int에 문제를 보았다.
첫 번째 생성자의 기본값을 잃을 수 있습니까? MyClass ()의 기본 생성자가되기 때문에 Args와 일치 할 수없는 경우 기본값도 가능합니다.
당신의 선택은 명시 적으로 const char *를 사용하는 생성자를 추가하는 것입니다 *
MyClass(const char* strPath, bool bLocation = false); // Thanks Andrew Grant!
또는
MyClass( string("blah") );
컴파일러는 본질적으로 const char *를 bool로 만드는 방법을 알고 있습니다. MyClass 생성자의 첫 번째 유형 유형의 MyClass 생성자에 대해 제공 한 소스 유형을 취할 수있는 생성자가 있는지 또는이를 수락 한 유형에 캐스팅 할 수 있는지 확인해야합니다. MyClass 생성자의 첫 번째 유형 유형의 생성자 또는 ... 글쎄, 당신은 이것이 어디로 가고 있는지 알 수 있으며 그것은 첫 번째 인수만을위한 것입니다. 그렇게하면 광기가 있습니다.
그만큼 explicit
키워드는 컴파일러에게 인수 유형의 값을 class의 객체로 변환 할 수 없다고 말합니다.
struct C { explicit C( int i ): m_i(i) {}; int m_i; };
C c = 10;//disallowed
C c( 2.5 ); // allowed
C ++에는 귀하의 경우에 어떤 생성자가 호출 될 것인지 결정하기위한 일련의 규칙이 있습니다. 머리 뒷면에서 알지 못하지만 기본 인수가 모호성으로 이어지는 것을 직관적으로 볼 수 있습니다.
당신은 그 불이행을 통해 생각해야합니다.
정적 인 건축 방법으로 떨어질 수 있습니다. 또는 다른 클래스 (디자인 관점에서 나쁜 선택이 아님)를 사용할 수 있습니다. 어느 쪽이든, 당신은 클라이언트 코드가 어떤 생성자를 사용할 것인지 결정하도록합니다.
struct C {
static C fromString( const char* s, const bool b = true );
static C fromBools( const bool abs = true, const bool b = true );
};
또는
struct CBase {
bool absolute;
bool location;
CBase( bool abs=true, bool loc=true );
};
struct CBaseFromPath {
// makes 'absolute' true if path is absolute
CBaseFromPath( const char* s, const bool loc );
};
당신은 확실한 그것이 실제로 첫 번째 생성자라고 부르는가? 당신은 끈으로 하드 코딩 된 문자열로 그것을 부르고 있습니까, 아니면 뒤에 숨겨져 있습니까? #define
? #define이 당신이 생각하는 것인지 확신합니까? (확장 된 사전 처리기 출력을 얻으려면 /ef 옵션으로 컴파일하고 통화가 보이기를 기대하는지 확인하십시오.)
편집 :이 의견과 다른 의견을 바탕으로 저의 제안은 다른 생성자를 추가하는 것입니다. const char*.
그게 가능합니까?