Você pode usar a palavra -chave explícita para evitar a conversão automática dos parâmetros do método?
-
05-07-2019 - |
Pergunta
Eu sei que você pode usar a palavra -chave C ++ 'explícita' para construtores de classes para evitar uma conversão automática do tipo. Você pode usar esse mesmo comando para evitar a conversão de parâmetros para um método de classe?
Eu tenho dois membros da classe, um que toma um bool como param, o outro um int. Quando liguei para a função com um int, o compilador converteu o param em um bool e chamou o método errado. Eu sei que eventualmente vou substituir o bool, mas por enquanto não quero quebrar as outras rotinas, pois essa nova rotina é desenvolvida.
Solução
Não, você não pode usar explícito, mas pode fazer isso:
class ClassThatOnlyTakesBoolsAndUIntsAsArguments
{
public:
void Method(bool arg1);
void Method(unsigned int arg1);
// Below just an example showing how to do the same thing with more arguments
void MethodWithMoreParms(bool arg1, SomeType& arg2);
void MethodWithMoreParms(unsigned int arg1, SomeType& arg2);
private:
template<typename T>
void Method(T arg1);
// Below just an example showing how to do the same thing with more arguments
template<typename T>
void MethodWithMoreParms(T arg1, SomeType& arg2);
};
Repita esse padrão para cada método que leva o bool
ou unsigned int
. Não forneça uma implementação para a versão templatizada do método.
Isso forçará o usuário a sempre chamar explicitamente a versão bool ou não assinado int.
Qualquer tentativa de ligar Method
com um tipo que não seja bool
ou unsigned int
deixará de compilar porque o membro é privado, sujeito às exceções padrão às regras de visibilidade, é claro (amigo, chamadas internas etc.). Se algo que tiver acesso chama o método privado, você receberá um erro de vinculador.
Outras dicas
Não. explicit
Impede a conversão automática entre classes específicas, independentemente do contexto. E é claro que você não pode fazer isso para aulas embutidas.
A seguir, é apresentado um invólucro muito básico que pode ser usado para criar um forte typedef:
template <typename V, class D>
class StrongType
{
public:
inline explicit StrongType(V const &v)
: m_v(v)
{}
inline operator V () const
{
return m_v;
}
private:
V m_v; // use V as "inner" type
};
class Tag1;
typedef StrongType<int, Tag1> Tag1Type;
void b1 (Tag1Type);
void b2 (int i)
{
b1 (Tag1Type (i));
b1 (i); // Error
}
Uma boa característica dessa abordagem é que você também pode distinguir entre parâmetros diferentes com o mesmo tipo. Por exemplo, você pode ter o seguinte:
class WidthTag;
typedef StrongType<int, WidthTag> Width;
class HeightTag;
typedef StrongType<int, HeightTag> Height;
void foo (Width width, Height height);
Ficará claro para os clientes de 'Foo' que argumento é qual.
Algo que pode funcionar para você é usar modelos. A seguir mostra a função de modelo foo<>()
sendo especializado para bool
, unsigned int
, e int
. o main()
A função mostra como as chamadas são resolvidas. Observe que as chamadas que usam uma constante int
que não especificam um sufixo de tipo foo<int>()
, então você receberá uma chamada de erro foo( 1)
Se você não se especializar em int
. Se for esse o caso, os chamadores que usam uma constante inteira literal terão que usar o "U"
Sufixo para obter a chamada para resolver (esse pode ser o comportamento que você deseja).
Caso contrário, você terá que se especializar em int
e use o "U"
sufixo ou lançar para um unsigned int
antes de passar para o unsigned int
Versão (ou talvez afirme que o valor não é negativo, se é isso que você deseja).
#include <stdio.h>
template <typename T>
void foo( T);
template <>
void foo<bool>( bool x)
{
printf( "foo( bool)\n");
}
template <>
void foo<unsigned int>( unsigned int x)
{
printf( "foo( unsigned int)\n");
}
template <>
void foo<int>( int x)
{
printf( "foo( int)\n");
}
int main ()
{
foo( true);
foo( false);
foo( static_cast<unsigned int>( 0));
foo( 0U);
foo( 1U);
foo( 2U);
foo( 0);
foo( 1);
foo( 2);
}
O Compiler deu aviso "Ambígue", que será suficiente.
Eu estava fazendo o desenvolvimento do TDD e não percebi que esqueci de implementar a chamada correspondente no objeto simulado.
O BOOL é um int que é limitado a 0 ou 1. Esse é o conceito inteiro de retorno 0;, é logicamente o mesmo que dizer, retornar false; (embora não use isso no código).
Você também pode escrever uma versão int que chama o BOOL One.