É uma boa idéia fornecer assinaturas de funções diferentes que façam a mesma coisa?

23

Aqui está uma classe C ++ que é construída com três valores.

class Foo{

    //Constructor
    Foo(std::string, int, char);

private:
    std::string foo;
    char bar;
    int baz;
};

Todos os tipos de parâmetros são diferentes.
Eu poderia sobrecarregar o construtor para que a ordem não importasse.

class Foo{

    //Constructors
    Foo(std::string, char, int);
    Foo(std::string, int, char);
    Foo(char, int, std::string);
    Foo(char, std::string, int);
    Foo(int, std::string, char);
    Foo(int, char, std::string);


private:
    std::string foo;
    char bar;
    int baz;
};

Mas isso é uma boa ideia?
Comecei a fazê-lo porque sabia de que coisas uma classe / função precisava;
Eu nem sempre me lembrava em que ordem eles os levavam.


Eu assumo que o compilador otimiza isso como se eu chamasse o mesmo construtor.

//compiler will implement this with the same code? 
//maybe not.. I could call a function to get a parameter, 
//and that function could change the state of the program, before calling
//a function to get another parameter and the compiler would have to
//implement both
Foo foo1("hello",1,'a');
Foo foo2('z',0,"world");

Quais são as suas opiniões sobre sobrecarregar uma função para que o pedido não seja importante?


Além disso, se estou escrevendo algumas funções utilitárias,
é uma boa idéia fornecer nomes de funções diferentes que façam a mesma coisa?

por exemplo.

void Do_Foo();
void DoFoo();
void do_foo();
//etc..

Não vejo frequentemente essas duas convenções semelhantes.
Devo quebrar ou adotar o hábito?

Trevor Hickey
fonte
1
Deveria-se apenas fazer esforço, fornecendo várias maneiras de expressar algo, se cada maneira explicitamente fornecida for, em alguns casos, clara e inequivocamente superior a qualquer uma das outras. Isso não significa que geralmente se deve se esforçar para garantir que algo possa ser escrito apenas de uma forma canônica, mas não faz sentido envidar esforços para permitir que algo seja especificado de alguma maneira que não seja a melhor.
supercat
Uma espécie de duplicata da minha pergunta aqui (agora concordo que é uma má ideia).
usar o seguinte comando

Respostas:

93

Eu poderia sobrecarregar o construtor para que a ordem [dos parâmetros] não importasse ... Mas isso é uma boa idéia?

Não.

Ter diferentes sobrecargas de construtor terá o efeito oposto ao que você pretende. O programador que vem depois de você espera que diferentes sobrecargas tenham um comportamento diferente e perguntará: "Que tipo de comportamento diferente está sendo expresso por cada uma dessas sobrecargas?

A maioria dos programadores espera a disciplina de ter parâmetros de método em uma ordem predefinida, e ferramentas como o IntelliSense lhes dirão a ordem esperada dos parâmetros à medida que eles os inserem.


Ter vários nomes de funções que fazem a mesma coisa é o mesmo problema; programadores esperam que as variantes tenham um comportamento diferente. Uma função ou método por comportamento, por favor, e apenas adote um padrão de nomeação consistente.

Robert Harvey
fonte
14
muitos votos positivos. Eu vou parar imediatamente. obrigado.
Trevor Hickey
8
Além disso, você não pode nomear construtores de maneira diferente para explicar seu objetivo, os leitores precisam inferir isso a partir dos parâmetros. Sobrecarregar o construtor dessa maneira torna muito mais difícil de entender.
Zachary Yates
3
"Tendo vários nomes de funções que fazem a mesma coisa ..." - por um tempo 'bom', observe as classes de Ruby, String Hash Array File .
+1. Você está lidando com desenvolvedores / programadores. A ideia da Microsoft de "usuário é macaco", não funciona aqui.
Manoj R
1
@ZacharyYates A falta de "nomes de construtores" pode ser contornada, expondo métodos de construção estáticos. Essa é uma prática padrão em Java, embora não tanto em C ++.
Xion
14

Às vezes, é necessário apoiar a comutação entre argumentos. Por exemplo:

double operator *(int, double);
double operator *(double, int);

Não queremos multiplicar an inte doublecalcular algo diferente se os operandos forem revertidos. Também não queremos forçar os programadores a lembrarem que, ao multiplicar ints e doubles, o valor doublefica à esquerda!

Não importa que seja um operador, porque o mesmo vale para:

footype plus(const footype &, const bartype &);
footype plus(const bartype &, const footype &);

Realmente depende dos tipos de função. Enquanto a maioria dos programadores provavelmente deseja suporte à comutatividade em bibliotecas aritméticas, eles não necessariamente desejam, digamos, uma biblioteca de E / S para suportar todas as possíveis ordens de argumentos.

A preocupação provavelmente depende do aninhamento esperado no qual as chamadas de função serão envolvidas. A flexibilidade nos operadores aritméticos permite alterar a estrutura geral da árvore de sintaxe para esclarecer a expressão geral: agrupar termos semelhantes e tal.

Kaz
fonte