A pergunta no tópico sugere uma confusão bastante comum. A confusão é bastante comum, que o C ++ FAQ defendeu contra o uso de virtuais privados, por um longo tempo, porque a confusão parecia ser uma coisa ruim.
Portanto, para se livrar da confusão primeiro: Sim, funções virtuais privadas podem ser substituídas nas classes derivadas. Os métodos de classes derivadas não podem chamar funções virtuais da classe base, mas podem fornecer sua própria implementação para eles. De acordo com Herb Sutter, ter uma interface pública não virtual na classe base e uma implementação privada que pode ser personalizada nas classes derivadas, permite uma melhor "separação da especificação da interface da especificação do comportamento personalizável da implementação". Você pode ler mais sobre isso em seu artigo "Virtualidade" .
Há, no entanto, mais uma coisa interessante no código que você apresentou, que merece mais atenção, na minha opinião. A interface pública consiste em um conjunto de funções não virtuais sobrecarregadas e essas funções chamam funções virtuais não públicas e não sobrecarregadas. Como de costume no mundo C ++, é um idioma, tem um nome e, claro, é útil. O nome é (surpresa, surpresa!)
"Públicos não virtuais sobrecarregados chamam virtuais não sobrecarregados protegidos"
Ajuda a gerenciar adequadamente a regra de ocultação . Você pode ler mais sobre isso aqui , mas tentarei explicar em breve.
Imagine que as funções virtuais da Engine
classe também são sua interface e é um conjunto de funções sobrecarregadas que não é virtual puro. Se fossem virtuais, ainda era possível encontrar o mesmo problema, conforme descrito abaixo, mas menor na hierarquia de classes.
class Engine
{
public:
virtual void SetState( int var, bool val ) {/*some implementation*/}
virtual void SetState( int var, int val ) {/*some implementation*/}
};
Agora vamos assumir que você deseja criar uma classe derivada e precisa fornecer uma nova implementação apenas para o método, que usa duas entradas como argumentos.
class MyTurbochargedV8 : public Engine
{
public:
// To prevent SetState( int var, bool val ) from the base class,
// from being hidden by the new implementation of the other overload (below),
// you have to put using declaration in the derived class
using Engine::SetState;
void SetState( int var, int val ) {/*new implementation*/}
};
Se você esqueceu de colocar a declaração de uso na classe derivada (ou redefinir a segunda sobrecarga), poderá ter problemas no cenário abaixo.
MyTurbochargedV8* myV8 = new MyTurbochargedV8();
myV8->SetState(5, true);
Se você não impediu a ocultação dos Engine
membros, a declaração:
myV8->SetState(5, true);
chamaria void SetState( int var, int val )
da classe derivada, convertendo true
para int
.
Se a interface não for virtual e a implementação virtual não for pública, como no seu exemplo, o autor da classe derivada terá menos um problema para pensar e pode simplesmente escrever
class MyTurbochargedV8 : public Engine
{
private:
void SetStateInt(int var, int val ) {/*new implementation*/}
};
A função virtual pura privada é a base do idioma da interface não virtual (OK, nem sempre é virtual pura , mas ainda é virtual). Obviamente, isso também é usado para outras coisas, mas acho isso mais útil (: em duas palavras: em uma função pública, você pode colocar algumas coisas comuns (como registro, estatísticas etc.) no início e no final da função e, em seguida, "no meio" para chamar essa função virtual privada, que será diferente para a classe derivada específica.
Virtual puro - apenas obriga as classes derivadas a implementá-lo.
EDIT : Mais sobre isso: Wikipedia :: NVI-idiom
fonte
Bem, por um lado, isso permitiria que uma classe derivada implementasse uma função que a classe base (contendo a declaração pura da função virtual) possa chamar.
fonte
EDIT: Declarações esclarecidas sobre a capacidade de substituir e a capacidade de acessar / chamar.
Ele poderá substituir essas funções privadas. Por exemplo, o exemplo inventado a seguir funciona ( EDIT: tornou privado o método da classe derivada e solte a invocação do método da classe derivada
main()
para demonstrar melhor a intenção do padrão de design em uso. ):Private
virtual
Os métodos em uma classe base como os do seu código geralmente são usados para implementar o padrão de design do Método de Modelo . Esse padrão de design permite alterar o comportamento de um algoritmo na classe base sem alterar o código na classe base. O código acima, onde os métodos da classe base são chamados por meio de um ponteiro da classe base, é um exemplo simples do padrão Método do Modelo.fonte
Engine
eDerivedEngine
não tem nada a ver com o queDerivedEngine
pode ou não pode substituir (ou acessar, nesse caso).O método virtual privado é usado para limitar o número de classes derivadas que podem substituir a função especificada. As classes derivadas que precisam substituir o método virtual privado precisarão ser amigas da classe base.
Uma breve explicação pode ser encontrada no DevX.com .
EDITAR Um método virtual privado é efetivamente usado no Template Method Pattern . As classes derivadas podem substituir o método virtual privado, mas as classes derivadas não podem chamá-lo de método virtual privado de classe base (no seu exemplo
SetStateBool
eSetStateInt
). Somente a classe base pode efetivamente chamar seu método virtual privado ( somente se as classes derivadas precisarem invocar a implementação básica de uma função virtual, torne a função virtual protegida ).Um artigo interessante pode ser encontrado sobre a virtualidade .
fonte
friend
pertencer à classe base. O Qt adotou a mesma abordagem ao implementar seu modelo de documento XML DOM.Resposta TL; DR:
Você pode tratá-lo como outro nível de encapsulamento - em algum lugar entre protegido e privado : você não pode chamá-lo da classe filho, mas pode substituí-lo.
É útil ao implementar o padrão de design do Método de Modelo . Você pode usar protegido , mas o privado, juntamente com o virtual, pode ser considerado a melhor opção, devido ao melhor encapsulamento.
fonte