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.