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).

Foi útil?

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?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top