Pergunta

Sim, eu entendo a diferença entre eles.O que eu quero saber é:por que SUBSTITUIR um método?O que é o bom em fazê-lo?Em caso de sobrecarga:a única vantagem é você não pensar em nomes diferentes para as funções?

Foi útil?

Solução

Sobrecarga geralmente significa que você tem duas ou mais funções no mesmo âmbito que tem o mesmo nome. A função que melhor corresponda aos argumentos quando uma chamada é feita vitórias e é chamado. Importante notar, em oposição ao chamar uma função virtual, é que a função que é chamado é selecionado em tempo de compilação. Tudo depende do tipo estático do argumento. Se você tem uma sobrecarga para B e um para D, eo argumento é uma referência a B, mas realmente aponta para um objeto D, em seguida, a sobrecarga para B é escolhido em C ++. Isso é chamado expedição estática em oposição à expedição dinâmica . Você sobrecarregar se você quiser fazer o mesmo que outra função com o mesmo nome, mas você quer fazer isso para outro tipo de argumento. Exemplo:

void print(Foo const& f) {
    // print a foo
}

void print(Bar const& bar) {
    // print a bar
}

ambos imprimir seu argumento, então eles estão sobrecarregados. Mas as primeiras impressões um foo, e as segundas impressões de um bar. Se você tem duas funções que fazem coisas diferentes, é considerado mau estilo quando eles têm o mesmo nome, porque isso pode levar a confusão sobre o que vai acontecer, na verdade, ao chamar as funções. Outro caso de uso para a sobrecarga é quando você tem parâmetros adicionais para as funções, mas o controle apenas para a frente a outras funções:

void print(Foo & f, PrintAttributes b) { 
    /* ... */ 
}

void print(Foo & f, std::string const& header, bool printBold) {
    print(f, PrintAttributes(header, printBold));
}

Isso pode ser conveniente para o chamador, se as opções que as sobrecargas tomar são usados ??frequentemente.

Substituir é algo completamente diferente. Ele não compete com a sobrecarga. Isso significa que se você tem uma função virtual em uma classe base, você pode escrever uma função com a mesma assinatura na classe derivada. A função na classe derivada substituições a função da base. Amostra:

struct base {
    virtual void print() { cout << "base!"; }
}

struct derived: base {
    virtual void print() { cout << "derived!"; }
}

Agora, se você tem um objeto e chamar a função membro print, a função de impressão do derivado é sempre chamado, porque ele substitui o da base. Se a função print não era virtual, em seguida, a função na derivada não substituir a função de base, mas seria apenas hide -lo. Substituindo pode ser útil se você tem uma função que aceita uma classe base, e cada um que é derivado dele:

void doit(base &b) {
    // and sometimes, we want to print it
    b.print();
}

Agora, mesmo em tempo de compilação o compilador só sabe que b é de pelo menos base, impressão da classe derivada será chamado. Esse é o ponto de funções virtuais. Sem eles, a função de impressão da base seria chamado, e aquele na classe derivada não iria substituí-lo.

Outras dicas

Isto irá adicionar mais alguma clareza aos pensamentos. enter descrição da imagem aqui

Você sobre load funções para três razões:

  1. Para fornecer duas (ou mais) funções que executam, coisas intimamente relacionadas semelhantes, diferenciados por tipos e / ou número de argumentos que aceita. exemplo artificial:

    void Log(std::string msg); // logs a message to standard out
    void Log(std::string msg, std::ofstream); // logs a message to a file
    
  2. Para fornecer duas (ou mais) formas de executar a mesma ação. exemplo artificial:

    void Plot(Point pt); // plots a point at (pt.x, pt.y)
    void Plot(int x, int y); // plots a point at (x, y)
    
  3. Para proporcionar a capacidade de efectuar uma acção equivalente dado duas (ou mais) diferentes tipos de entrada. exemplo artificial:

    wchar_t      ToUnicode(char c);
    std::wstring ToUnicode(std::string s);
    

Em alguns casos vale a pena, argumentando que a função de um nome diferente é uma escolha melhor do que uma função sobrecarregada. No caso de construtores, a sobrecarga é a única opção.


Sobre montando a função é completamente diferente, e serve a um propósito totalmente diferente. Função primordial é como polimorfismo funciona em C ++. Você substituir uma função para alterar o comportamento dessa função em uma classe derivada. Desta forma, uma classe base fornece interface, ea classe derivada fornece implementação.

Substituir é útil quando você herda de uma classe base e pretendam ampliar ou modificar a sua funcionalidade. Mesmo quando o objeto é lançado como a classe base, ele chama a sua função substituída, não a base.

A sobrecarga não é necessário, mas certamente torna a vida mais fácil ou mais legíveis às vezes. Sem dúvida ele pode torná-lo pior, mas isso é quando ele não deve ser usado. Por exemplo, você pode ter duas funções que executam a mesma operação, mas agir em diferentes tipos de coisas. Por exemplo Divide(float, float) deve ser diferente do Divide(int, int), mas eles são basicamente a mesma operação. Você não gostaria de lembrar um nome do método, "Divide", que tem que se lembrar "DivideFloat", "DivideInt", "DivideIntByFloat", e assim por diante?

As pessoas já definidos tanto a sobrecarga e substituindo, então não vou discorrer.

ASAFE perguntou:

a única vantagem de sobrecarga] é você não pensar em vários nomes de funções?

1.Você não tem que pensar em vários nomes

E isso já é uma poderosa vantagem, não é?

Vamos comparar com o conhecido funções da API C, e a sua ficção C++ variantes:

/* C */
double fabs(double d) ;
int abs(int i) ;

// C++ fictional variants
long double abs(long double d) ;
double abs(double d) ;
float abs(float f) ;
long abs(long i) ;
int abs(int i) ;

Isso significa duas coisas:Um, você deve informar ao compilador o tipo de dados que ele irá alimentar para a função de escolha de função direita.Dois, se você deseja estender-lo, você precisará encontrar nomes de fantasia, e o usuário de suas funções terá que lembre o direito de nomes de fantasia.

E tudo o que ele/Ela queria era ter o valor absoluto de alguns variável numérica...

Uma ação significa uma e apenas uma função de nome.

Observe que você não está limitado para alterar o tipo de um parâmetro.Tudo pode mudar, desde que não faz sentido.

2.Para os operadores, é obrigatório

Vamos ver de operadores:

// C++
Integer operator + (const Integer & lhs, const Integer & rhs) ;
Real operator + (const Real & lhs, const Real & rhs) ;
Matrix operator + (const Matrix & lhs, const Matrix & rhs) ;
Complex operator + (const Complex & lhs, const Complex & rhs) ;

void doSomething()
{
   Integer i0 = 5, i1 = 10 ;
   Integer i2 = i0 + i1 ; // i2 == 15

   Real r0 = 5.5, r1 = 10.3 ;
   Real r2 = r0 + r1 ; // r2 = 15.8

   Matrix m0(1, 2, 3, 4), m1(10, 20, 30, 40) ;
   Matrix m2 = m0 + m1 ; // m2 == (11, 22, 33, 44)

   Complex c0(1, 5), c1(10, 50) ;
   Complex c2 = c0 + c1 ; // c2 == (11, 55)
}

No exemplo acima, você quer para evitar o uso de qualquer coisa que não seja o operador+.

Note que C tem implícito sobrecarregar do operador para tipos internos (incluindo C99 tipo complexo):

/* C */
void doSomething(void)
{
   char c = 32 ;
   short s = 54 ;
   c + s ; /* == C++ operator + (char, short) */
   c + c ; /* == C++ operator + (char, char) */
}

Assim, mesmo em não-objeto idiomas, esta sobrecarga coisa é utilizado.

3.Para objetos, é obrigatória

Vamos ver o uso de um objeto de métodos básicos:Seus construtores:

class MyString
{
   public :
      MyString(char character) ;
      MyString(int number) ;
      MyString(const char * c_style_string) ;
      MyString(const MyString * mySring) ;
      // etc.
} ;

Alguns poderiam considerar isto como função de sobrecarga, mas, na verdade, é mais semelhante ao operador de sobrecarga:

void doSomething()
{
   MyString a('h') ;                  // a == "h" ;
   MyString b(25) ;                   // b == "25" ;
   MyString c("Hello World") ;        // c == "Hello World" ;
   MyString d(c) ;                    // d == "Hello World" ;
}

Conclusão:A sobrecarga é legal

No C, quando você dar o nome da função, os parâmetros são implicitely parte da assinatura na chamada.Se você tem "duplo fab(double d)" e, em seguida, enquanto a assinatura da fab para o compilador é o undecorated "fab", isso significa que você deve saber que leva apenas duplica.

Em C++, o nome da função não significa que sua assinatura é forçado.A sua assinatura a chamada de seu nome e seus parâmetros.Assim, se você escrever abs(-24), o compilador irá saber que a sobrecarga do abs tem de chamar, e você, ao escrevê-lo, encontrá-lo mais natural:Você deseja que o valor absoluto de -24.

De qualquer maneira, quem codificadas um pouco em qualquer idioma, com os operadores já usa a sobrecarga, seja C ou Basic numérica operadores, Java concatenação de seqüência de caracteres, C# delegados, etc..Por quê? porque é mais natural.

E os exemplos acima são apenas a ponta do iceberg:Quando utilizar modelos, sobrecarregando-se tornar muito útil, mas isso é outra história.

O exemplo clássico é animal classe com speak () método. Substitui o cão subclasse falar () a "casca", enquanto substituições do gato subclasse falar () para "miau".

Um uso de sobrecarga é para uso em templates. Em modelos, você escrever um código que pode ser usado em diferentes tipos de dados, e chamá-lo com diferentes tipos. Se funções que recebem diferentes argumentos tiveram de ser nomeados de forma diferente, o código para diferentes tipos de dados que, em geral, tem que ser diferente, e modelos apenas não iria funcionar.

Enquanto você não pode escrever modelos, no entanto, você está quase certo com alguns deles. Streams são modelos, e por isso são vetores. Sem sobrecarregar, e, portanto, sem modelos, você precisa chamar Unicode córregos algo diferente a partir de fluxos ASCII, e você teria que usar matrizes e ponteiros em vez de vetores.

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