A palavra-chave 'substituir' é apenas uma verificação de um método virtual substituído?


226

Pelo que entendi, a introdução da overridepalavra-chave no C ++ 11 não passa de uma verificação para garantir que a função que está sendo implementada seja a entrada overridede uma virtualfunção na classe base.

É isso?


50
Sim.⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣⁣
— R. Martinho Fernandes

13
Não é uma verificação dupla. É o único cheque.
— Nikos C.

13
ei, substituir NÃO é uma palavra-chave, é uma espécie de açúcar gramatical. substituição int = 42; // OK
— KAlO2

2
Além disso, melhora a legibilidade, explicando que a função declarada é substituída;)
— mots_g

5
Então, uh ... Quando o C ++ 11 se tornará padrão o suficiente para que eles comecem a ensinar coisas desse tipo nos meus 4 anos locais? Quando eles vão saber ?!
— Cinch

Respostas:


263

Essa é realmente a ideia. O ponto é que você é explícito sobre o que quer dizer, para que um erro silencioso possa ser diagnosticado:

struct Base
{
    virtual int foo() const;
};

struct Derived : Base
{
    virtual int foo()   // whoops!
    {
       // ...
    }
};

O código acima é compilado, mas não é o que você quis dizer (observe a falta const). Se você dissesse,virtual int foo() override isso, receberá um erro do compilador de que sua função não está substituindo nada.


74
+1: Embora, infelizmente, seja um arenque vermelho quando as pessoas sugerem que o novo overriderecurso "corrige" isso; você tem que lembrar de usá-lo, assim como você deve ter se lembrado para escrever os const;)
— Leveza raças em órbita

Acabei de perceber que explicitas definições de classe não chegaram ao C ++ 11. Hã.
— aschepler

1
@aschepler E o que uma explicitdefinição de classe faria? Nunca ouvi falar sobre isso.
— Christian Rau

18
@LightnessRacesinOrbit: Sim, não é à prova de idiotas; no entanto, lembrar de uma regra geral (de escrever loucamente overridequando se pretende fazê-lo) é mais provável do que lembrar de casos de canto, ou seja, não há generalidade em copiar funções de diferentes protótipos, apenas irregularidades como falta constou escrita em charvez de intetc.
— legends2k

1
@ Light, o melhor caso de uso do overrideespecificador é mencionado nesta resposta , que é mais futurista do que imediata. A resposta sugere que, mantenha overrideo virtualmétodo. No futuro, quando um engano altera a assinatura, seus chutes utilidade.
— iammilind

35

Citação da Wikipedia:

O identificador especial de substituição significa que o compilador verificará as classes base para ver se há uma função virtual com essa assinatura exata. E se não houver, o compilador irá errar.

http://en.wikipedia.org/wiki/C%2B%2B11#Explicit_overrides_and_final

Editar (tentando melhorar um pouco a resposta):

Declarar um método como "substituir" significa que esse método se destina a reescrever um método (virtual) na classe base. O método de substituição deve ter a mesma assinatura (pelo menos para os parâmetros de entrada) que o método que pretende reescrever.

Por que isso é necessário? Bem, os dois casos de erro comuns a seguir são impedidos:

  1. um digita errado um tipo no novo método. O compilador, sem saber que pretende escrever um método anterior, simplesmente o adiciona à classe como um novo método. O problema é que o método antigo ainda está lá, o novo é adicionado apenas como uma sobrecarga. Nesse caso, todas as chamadas para o método antigo funcionarão como antes, sem nenhuma alteração no comportamento (que teria sido o próprio objetivo da reescrita).

  2. esquece-se de declarar o método na superclasse como "virtual", mas ainda tenta reescrevê-lo em uma subclasse. Embora isso seja aparentemente aceito, o comportamento não será exatamente como pretendido: o método não é virtual; portanto, o acesso através de ponteiros para a superclasse terminará de chamar o método antigo (superclasse ') em vez do método novo (subclasse').

Adicionar "substituir" claramente desambigua isso: com isso, diz-se ao compilador que três coisas estão esperando:

  1. existe um método com o mesmo nome na superclasse
  2. esse método na superclasse é declarado como "virtual" (ou seja, destinado a ser reescrito)
  3. o método na superclasse possui a mesma assinatura (entrada *) que o método na subclasse (o método de reescrita)

Se alguma dessas opções for falsa, um erro será sinalizado.

* note: o parâmetro de saída às vezes é de tipo diferente, mas relacionado. Leia sobre transformações covariantes e contravariantes, se estiver interessado.


31

" Substituir " encontrado é útil quando alguém atualiza a assinatura do método virtual da classe base, como adicionar um parâmetro opcional, mas se esquece de atualizar a assinatura do método da classe derivada. Nesse caso, os métodos entre a base e a classe derivada não são mais uma relação polimórfica. Sem a declaração de substituição, é difícil descobrir esse tipo de bug.


1
+1. Embora overrideseja uma ótima maneira de descobrir esses problemas, uma boa cobertura de teste de unidade também deve ajudar.
— Desiludido

1
É exatamente por isso que estou tão empolgado com esse novo especificador. O único problema é que esse recurso já deve ser aplicado para evitar erros causados ​​por alterações nas classes base. ;-)
— Wolf


2

Rascunho padrão do C ++ 17

Após examinar todos os overridehits no rascunho padrão do C ++ 17 N4659 , a única referência que posso encontrar para o overrideidentificador é:

5 Se uma função virtual é marcada com a substituição virt-specifier e não substitui uma função membro de uma classe base, o programa não está formado. [Exemplo:

struct B {
  virtual void f(int);
};

struct D : B {
  virtual void f(long) override; // error: wrong signature overriding B::f
  virtual void f(int) override;  // OK
}

- exemplo final]

então eu acho que possivelmente explodir programas errados é realmente o único efeito.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.