Qual é o objetivo da final
palavra - chave no C ++ 11 para funções? Entendo que isso evita a substituição de funções por classes derivadas, mas se for esse o caso, não basta declarar como não virtuais suas final
funções? Há outra coisa que estou perdendo aqui?
143
virtual
palavra - chave ou não.func
não é virtual; portanto, não há nada a substituir e, portanto, nada a ser marcado comooverride
oufinal
.Respostas:
O que está faltando, como idljarn já mencionado em um comentário, é que, se você estiver substituindo uma função de uma classe base, não poderá marcá-la como não virtual:
fonte
virtual
pode causar erros, e o C ++ 11 adicionou aoverride
tag a uma função que detectará essa situação e falhará na compilação quando uma função que pretende substituir realmente ocultaÉ para impedir que uma classe seja herdada. Da Wikipedia :
Também é usado para marcar uma função virtual para impedir que ela seja substituída nas classes derivadas:
A Wikipedia ainda faz um ponto interessante :
Isso significa que o seguinte é permitido:
fonte
"final" também permite que uma otimização do compilador ignore a chamada indireta:
com "final", o compilador pode chamar
CDerived::DoSomething()
diretamente de dentroBlah()
, ou até mesmo inline. Sem ele, ele deve gerar uma chamada indireta dentro doBlah()
porqueBlah()
poderia ser chamado dentro de uma classe derivada que foi substituídaDoSomething()
.fonte
Nada a acrescentar aos aspectos semânticos de "final".
Mas eu gostaria de acrescentar ao comentário de chris green que "final" pode se tornar uma técnica de otimização de compilador muito importante em um futuro não tão distante. Não apenas no caso simples que ele mencionou, mas também para hierarquias de classe do mundo real mais complexas que podem ser "fechadas" por "final", permitindo assim aos compiladores gerar código de despacho mais eficiente do que com a abordagem vtable usual.
Uma desvantagem principal do vtables é que, para qualquer objeto virtual (assumindo 64 bits em uma CPU Intel típica), o ponteiro sozinho consome 25% (8 de 64 bytes) de uma linha de cache. No tipo de aplicativos que gosto de escrever, isso dói muito. (E, pela minha experiência, é o argumento número 1 contra o C ++ do ponto de vista purista do desempenho, isto é, pelos programadores em C.)
Em aplicativos que exigem desempenho extremo, o que não é tão incomum para o C ++, isso pode realmente se tornar incrível, não sendo necessário contornar esse problema manualmente no estilo C ou no malabarismo estranho de modelos.
Essa técnica é conhecida como Desirtualização . Um termo que vale a pena lembrar. :-)
Há um excelente discurso recente de Andrei Alexandrescu que explica muito bem como você pode solucionar essas situações hoje e como "final" pode fazer parte da solução de casos semelhantes "automaticamente" no futuro (discutido com os ouvintes):
http://channel9.msdn.com/Events/GoingNative/2013/Writing-Quick-Code-in-Cpp-Quickly
fonte
Final não pode ser aplicado a funções não virtuais.
Não seria muito significativo poder marcar um método não virtual como 'final'. Dado
a->foo()
sempre ligaráA::foo
.Mas, se A :: foo estivesse
virtual
, então B :: foo o substituiria. Isso pode ser indesejável e, portanto, faria sentido tornar a função virtual final.A questão é, porém, por que permitir final em funções virtuais. Se você tem uma hierarquia profunda:
Em seguida,
final
coloca um "piso" sobre o quanto a substituição pode ser feita. Outras classes podem estender A e B e substituir suasfoo
, mas se uma classe estender C, não será permitido.Portanto, provavelmente não faz sentido fazer o 'nível superior'
final
, mas pode fazer sentido mais abaixo.(Acho que há espaço para estender as palavras final e substituir os membros não virtuais. Eles teriam um significado diferente.)
fonte
final
. Por exemplo, se você sabe que deseja tudoShape
-foo()
algo predefinido e definido que nenhuma forma derivada deve modificar. Ou, estou errado e há um padrão melhor para empregar nesse caso? EDIT: Ah, talvez porque, nesse caso, não se deva simplesmente subir ao nível superiorfoo()
virtual
? Mas ainda assim, ele pode ser escondido, mesmo se chamado corretamente (polymorphically) viaShape*
...Um caso de uso para a palavra-chave 'final' de que gosto é o seguinte:
fonte
final
adiciona uma intenção explícita de não ter sua função substituída e causará um erro do compilador caso isso seja violado:Como o código está, ele compila e
B::foo
substituiA::foo
.B::foo
A propósito, também é virtual. No entanto, se mudarmos o número 1 paravirtual int foo() final
, esse é um erro do compilador e não podemos substituirA::foo
mais nas classes derivadas.Observe que isso não nos permite "reabrir" uma nova hierarquia, ou seja, não há como criar
B::foo
uma nova função não relacionada que possa estar independentemente à frente de uma nova hierarquia virtual. Depois que uma função é final, ela nunca pode ser declarada novamente em nenhuma classe derivada.fonte
A palavra-chave final permite declarar um método virtual, substituí-lo N vezes e depois exigir que 'isso não possa mais ser substituído'. Seria útil restringir o uso de sua classe derivada, para que você possa dizer "Eu sei que minha super classe permite que você substitua isso, mas se você quiser derivar de mim, não poderá!".
Como outros pôsteres apontaram, ele não pode ser aplicado a funções não virtuais.
Um objetivo da palavra-chave final é impedir a substituição acidental de um método. No meu exemplo, DoStuff () pode ter sido uma função auxiliar que a classe derivada simplesmente precisa renomear para obter o comportamento correto. Sem final, o erro não seria descoberto até o teste.
fonte
A palavra-chave final em C ++, quando adicionada a uma função, impede que ela seja substituída por uma classe base. Além disso, quando adicionado a uma classe, impede a herança de qualquer tipo. Considere o exemplo a seguir, que mostra o uso do especificador final. Este programa falha na compilação.
Além disso:
fonte
Suplemento à resposta de Mario Knezović:
O código acima mostra a teoria, mas não foi realmente testado em compiladores reais. Muito apreciado se alguém colar uma saída desmontada.
fonte