errado argumento de conversão preferido quando chamar a função
-
20-08-2019 - |
Pergunta
Eu estou escrevendo um programa em MS Visual C++ 6.0 (sim, eu sei que é antigo, não há nada que eu possa fazer para atualizar).Eu estou vendo algum comportamento que eu acho que é realmente estranho.Eu tenho uma classe com dois construtores definidos como este:
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;
};
Quando eu criar uma instância da classe com esta sintaxe: MyClass("blah")
, ele chama o primeiro construtor.Como você pode ver, eu adicionei o explicit
palavra-chave para ele na esperança de que ele não iria fazer isso...não há dados.Ele parece preferir a conversão de const char *
para bool
sobre a conversão para RWCString
, que tem um construtor de cópia que leva uma const char *
.Por que é que ele faz isso?Eu diria que, dadas duas opções possíveis, como este, seria dizer que é ambíguo.O que posso fazer para impedi-lo de fazer isso?Se possível, eu gostaria de evitar ter que explicitamente o strPath
argumento para um RWCString
, como vai ser usado com literais muito e isso é um monte de digitação extra (além de um muito fácil de erro).
Solução
O explícito não ajudará aqui, pois o construtor não faz parte da conversão implícita, apenas o destinatário.
Não há como controlar a ordem preferida das conversões, mas você pode adicionar um segundo construtor que levou um const char*. Por exemplo:
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;
};
Outras dicas
Andrew Grant desde que a solução.Eu quero dizer a você por ele não funciona do jeito que você tentou.Se você tiver dois viável funções para um argumento, então, o que corresponde ao argumento melhor é chamado.A segunda exige uma conversão definida pelo usuário, enquanto que o primeiro apenas precisa de um padrão de conversão.É por isso que o compilador prefere o primeiro sobre o segundo.
Se você não quiser continuar lançando, parece -me que você pode ter que fazer outro ctor que leva um const char*.
Isso é o que eu provavelmente faria nessa situação.
(Não sei por que você está fazendo um CTOR com um tipo que não está passando para a maior parte de seu uso.)
editar:
Eu vejo alguém já postou isso enquanto eu estava digitando o meu
Não sabe por que isso deve confundir uma referência a uma string e a um bool? Eu já vi problemas com um bool e um int.
Você pode perder o valor padrão para o primeiro construtor - pode ser que, uma vez que isso está tornando -o o construtor padrão do myClass (), também é o padrão se não puder corresponder aos args
Suas opções são adicionar um construtor que explicitamente leva um const char *
MyClass(const char* strPath, bool bLocation = false); // Thanks Andrew Grant!
Ou faça
MyClass( string("blah") );
O compilador sabe intrinsecamente como transformar um char * em um bool. Teria que procurar ver se, para qualquer um dos tipos de primeiro argumento de construtores myclass, há um construtor que levará o tipo de fonte que você deu ou se pode lançá-lo para um tipo que é aceito por Qualquer um dos construtores de qualquer um dos tipos de primeiro argumento de seus construtores myclass, ou ... bem, você vê para onde está indo e isso é apenas para o primeiro argumento. Dessa forma, reside a loucura.
o explicit
A palavra -chave diz ao compilador que não pode converter um valor do tipo do argumento em um objeto de sua classe implicitamente, como em
struct C { explicit C( int i ): m_i(i) {}; int m_i; };
C c = 10;//disallowed
C c( 2.5 ); // allowed
O C ++ tem um conjunto de regras para determinar qual construtor deve ser chamado no seu caso - não sei do fundo da minha cabeça, mas você pode ver intuitivamente que os argumentos padrão levam à ambiguidade.
Você precisa pensar nesses padrões.
Você pode falar sobre alguns métodos estáticos de construção. Ou você pode usar uma classe diferente (que não é uma má escolha do ponto de vista do design). De qualquer maneira, você permite que o código do cliente decida qual construtor usar.
struct C {
static C fromString( const char* s, const bool b = true );
static C fromBools( const bool abs = true, const bool b = true );
};
ou
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 );
};
Você é certo Que realmente está chamando o primeiro construtor? Você está chamando isso com a corda codificada ou está escondida atrás de um #define
? Tem certeza de que o #Define é o que você acha que é? (Tente compilar com a opção /EF para obter a saída de pré -processador expandida e veja se a chamada parece que você esperaria.)
Editar: Com base neste e em outros comentários, minha sugestão é adicionar outro construtor para const char*.
Isso é viável?