Obra: Programar em C++/Herança
Matéria: Filosofia
conceito herança um dos pontos chave de programação orientada objetos poo ela fornece meios de promover extensibilidade do código reutilização uma maior coerência lógica no modelo de implementação estas características nos possibilitam diversas vantagens principalmente quando mantemos bibliotecas para uso futuro de determinados recursos que usamos com muita frequência uma classe de objetos veiculo por exemplo contém todas as características inerentes aos veículos como combustível autonomia velocidade máxima etc agora podemos dizer que carro uma classe que têm as características básicas da classe veículo mais as suas características particulares analisando esse fato podemos concluir que poderíamos apenas definir em carro suas características usar veículo de alguma forma que pudéssemos lidar com as características básicas este meio chama se herança agora podemos definir outros tipos de veículos como moto caminhão trator helicóptero etc sem ter que reescrever parte que está na classe veículo para isso define se classe veículo com suas características depois cria se classes específicas para cada veículo em particular declarando se parentesco neste instante outro exemplo imagine que já exista uma classe que defina comportamento de um dado objeto da vida real por exemplo animal uma vez que eu sei que leão um animal que se deve fazer aproveitar classe animal fazer com que classe leão derive herde da classe animal as características comportamentos que mesma deve apresentar que são próprios dos indivíduos classificados como animais ou seja herança acontece quando duas classes são próximas têm características mútuas mas não são iguais existe uma especificação de uma delas portanto em vez de escrever todo código novamente possível poupar algum tempo dizer que uma classe herda da outra depois basta escrever código para especificação dos pontos necessários da classe derivada classe que herdou sintaxe para declarar uma classe derivada de outra já existente procedemos de forma declarar parentesco grau de visibilidade acesso que classe derivada terá dos membros de sua classe base para isso seguimos seguinte código sintático class classe_derivada classe_base corpo da classe derivada repare que temos operador dois pontos como elo entre as duas classes este operador promove parentesco entre as duas classes quando usado na declaração de uma classe derivada termo opcional mas se estiver presente deve ser public private ou protected ele define grau de visibilidade dos membros da classe base quando classe derivada precisar acessá los exemplo de implementação demonstra herança include using namespace std class define uma classe base veículos int rodas int passageiros public void set_rodas int num rodas num int get_rodas return rodas void set_pass int num passageiros num int get_pass return passageiros class caminhao public define um caminhao int carga public void set_carga int size carga size int get_carga return carga void mostrar enum tipo car van vagao class automove
a int size carga size int get_carga return carga void mostrar enum tipo car van vagao class automovel public define um automovel enum tipo car_tipo public void set_tipo tipo car_tipo enum tipo get_tipo return car_tipo void mostrar void caminhao mostrar cout na implementação acima temos classe base duas classes derivadas caminhao automovel podemos notar que as características comuns todos os tipos de veículos rodas passageiros estão na classe base enquanto as características exclusivas de cada tipo de veículo estão nas classes derivadas desta forma podemos definir procedimentos especializados para cada classe fazendo com que todas as eventuais modificações feitas ao longo da implementação na classe base sejam estendidas todos os objetos criados partir das classes derivadas no programa repare ainda um pormenor tanto classe caminhao quanto automovel têm como função membro método mostrar mas uma não interfere com outra isto ilustra um outro aspecto da orientação objeto polimorfismo este será exposto em mais detalhe nos capítulos subsequentes controle de acesso classe base quando uma classe herda outra os membros da classe base são incorporados como membros da classe derivada devido separação das classes do controle de acesso às variáveis em cada classe devemos pensar como as restrições de acesso são gerenciadas em classes diferentes principalmente acesso membros da classe base partir das classes derivadas acesso dos membros da classe base classe derivada determinado pelo especificador de acesso public private protected por defaut padrão temos private ou seja como temos opção de não explicitar especificador de acesso se este não estiver presente compilador usará private durante interpretação do código assim ficamos com as possíveis combinações classe base herdada como public membros públicos public da classe base como se copiássemos os membros da classe base os colocássemos como public na classe derivada no final eles permanecem como públicos membros privados private da classe base os membros estão presentes na classe porém ocultos como privados desta forma as informações estão presentes mas só podem ser acessadas através de funções publicas ou protegidas da classe base membros protegidos protected da classe base se tivermos membros protegidos protected na classe derivada eles se comportam como se tivessem sido copiados para classe derivada como protegidos protected classe base herdada como private membros públicos public da classe base os membros se comportam como se tivessem sido copiados como privados private na classe derivada membros privados private da classe base os membros estão presentes na classe porém ocultos como privados desta forma as informações estão presentes mas não poderão ser acessadas não ser por funções da classe base que se utilizem delas membros protegidos protected da classe base os membros se comportam como se tivessem sido copiados como privados private na classe derivada classe base herdada como protected membros públicos p
iados como privados private na classe derivada classe base herdada como protected membros públicos public da clase base se comportam como se tivéssemos copiado os como protegidos protected na classe derivada membros privados private da classe base os membros estão presentes na classe porém ocultos como privados desta forma as informações estão presentes mas não poderão ser acessadas não ser por funções da classe base que se utilizem delas membros protegidos protected da classe base se comportam como se estivéssemos copiado os como protegidos protected na classe derivada em suma estas regras podem ser sintetizadas em uma regra muito simples prevalece atributo mais restritivo para isto basta nos listar os atributos por ordem de restrições decrescente private protected public assim temos todas as combinações definidas quando colocamos um atributo combinado com outro bastando para isto escolher sempre mais restritivo na combinação por exemplo quando temos uma variável pública na base herança privada combinação resulta em uma variável privada na classe derivada aqui está um exemplo muito simples include using namespace std class base int public void set int int void show cout conseguimos acessar as funções set show porque são heradadas como publicas agora modifiquemos atributo de acesso na declaração da herança da classe base include using namespace std class base int public void set int int void show cout agora já não podemos acessar as funções porque estão privadas heranças múltiplas podemos ter situação em que uma classe derivada possa herdar membros de várias classes base esta característica uma distinção entre outras linguagens orientadas objeto este recurso dá mais poder de modelagem ao programador mas vale pena lembrar que mais poder exige mais cautela no uso um exemplo de múltiplas classes base include using namespace std class base protected int public void showx cout repare que utilizamos operador vírgula para dizer ao compilador que classe derivada herda mais de uma classe com efeito temos uma lista de classes separadas por vírgulas depois do operador dois pontos quando queremos que classe derivada herde uma classe como pública outra como privada ou protegida basta preceder classe com seu especificador de acesso da mesma forma omissão do especificador leva compilador usar padrão que privado private construtores destrutores temos uma série de classes que mantém relações de parentesco conforme mostramos nas seções anteriores em termos genéricos classes que herdam características de uma base precisam de regras claras quando forem criadas destruídas precisamos definir sequência em que os construtores destrutores serão chamados uma vez que cada classe tem pelo menos um construtor um destrutor agora temos questão quando que os construtores são chamados quando eles são herdados quando um objeto da classe derivada instanciado construtor da classe base chamado primeiro seguido do construtor das classes derivadas em sequência da base até última class
e chamado primeiro seguido do construtor das classes derivadas em sequência da base até última classe derivada quando objeto da classe derivada destruído seu destrutor chamado primeiro seguido dos destrutores das outras classes derivadas logo abaixo em sequência até base vamos testar ver como isto funciona no caso em que termos herança sequencial teremos include using namespace std class base public base cout caso de múltipla herança include using namespace std class base public base cout neste caso sequência de inicialização segue ordem estabelecida na lista de herança mais explicitamente temos construção das bases base base nesta ordem respectivamente depois derivada que automaticamente nos revela sequência de destruição na ordem inversa ou seja destroi se derivada depois base finalmente estrutura da base passando parâmetros para construtores da classe base agora imaginemos que temos um conjunto de bases para uma classe que queiramos derivar então podemos ter um construtor em cada base que precise de parâmetros para que possa ser invocado pela nossa classe como poderemos passar os parâmetros uma vez que os mesmos só podem ser passados durante inicialização da classe para que possamos passar os parâmetros para as classes bases durante inicialização do objeto da classe derivada temos recurso de passagem de parâmetros pelo construtor basicamente ele funciona como se passássemos valores para variáveis membro chamamos cada construtor na lista de passagem de valores sintax para declarar corpo do construtor seguinte class classe_derivada public base public base public basen membros public classe_derivada outras funções classe_derivada classe_derivada base base basen corpo do construtor da classe derivada este exemplo um pouco mais complexo atenção include using namespace std class base protected int public base int cout no exemplo construtor da classe derivada declarado com argumentos no entanto função derivada usa apenas um para inicializar variável interna da classe segundo argumento usado para passar valor de inicialização para classe base vejamos mais um exemplo include using namespace std class base protected int public base int cout superposição de funções muitas vezes temos classes derivadas que executam uma determinada ação de forma distinta da mesma ação definida na classe base por exemplo se temos uma classe animal declaramos uma função chamada mover depois declaramos duas derivadas ave peixe com mesma função mover teremos uma incoerência devido ao fato de que peixes se movem de forma totalmente diferente de aves uma vez que peixes devem nadar aves podem voar ou andar nosso modelo de objetos está incorreto por questões de coerência semântica porém precisamos manter mesmo nome para as funções das classes base derivada em algumas construções isto essencial devido necessidade de criarmos objetos generalistas por exemplo se tivermos classes ave peixe abstraídas em uma base animal como vimos acima havendo estas condições como poderemos criar comp
ixe abstraídas em uma base animal como vimos acima havendo estas condições como poderemos criar comportamentos diferentes usando mesmo nome para as funções resposta está em uma das características que será muito útil quando quisermos usar de polimorfismo que iremos abordar em capítulo específico mais adiante ocultação superposição de funções da classe base partir de uma classe derivada conhecida como overriding em manuais de compiladores com este recurso podemos declarar em uma classe derivada uma função com nome parâmetros idênticos uma existente em uma classe base porém com conteúdo diferente vejamos exemplo de código teremos uma noção mais concreta do que foi explanado include using namespace std class animal public void comer void mover void dormir cout ao executar programa gerado por este código percebemos que mesma função mover terá comportamento diferente quando invocada por objetos de classes diferentes programa mostrará mensagem nadando para função invocada pelo objeto sardinha voando para invocada pelo objeto passarinho aqui mecanismo bem simples de se entender quando cada objeto tem uma versão diferente para mesma função fácil para compilador relacionar objeto classe que ele pertence invocar função apropriada acessando funções superpostas da classe base mecanismo para obter acesso às classes base partir da classe derivada intuitivo para isto usamos operador de resolução de escopo composto por um par de dois pontos usando seguinte sintaxe ou seja basta invocar função informando qual versão específica que se deseja utilizar se tivermos uma classe outra com uma função print por exemplo quisermos usar função print da classe fazemos print talvez seja melhor visualizar um exemplo no código mais completo class public void print cout ver também programação orientada objetos herança conceito