Ponteiros com classes e objetos
Teoria
E aí pessoal, aqui é o Juan do Responde Aí, e hoje vamos falar um pouco de como os ponteiros se relacionam com a Programação Orientada a Objetos
Ponteiros que apontam para objetos
Para criar um ponteiro a gente vem usando a seguinte forma:
Quando a gente trabalha com objetos, fazemos a mesmas coisas, porém o que vai ser trabalhado é a própria classe.
Os operadores de endereço e de desreferenciação continuam funcionando do mesmo jeito. Então, na hora de acessar o conteúdo de um objeto primeiro devemos usar o operador para acessar o objeto, e em seguida usar o operador ponto para acessar ao conteúdo:
É necessário usar os parêntesis para que o processo ocorra na ordem correta: primeiro acessar o objeto, depois acessar os métodos e atributos.
Exemplo: Crie um ponteiro que acesse um atributo e um método de um objeto.
Pra começar, vamos criar uma classe que tenha um atributo e um método quaisquer:
Vamos criar uma instância desse objeto:
E em seguida vamos criar um ponteiro para o tipo
Usando o operador de endereço, vamos fazer o apontar para
A gente pode usar o para acessar o objeto, e em seguida usar operador ponto para acessar os métodos e atributos.
Operador seta
Você pode ter notado que a forma de acessar um atributo ou método através de um ponteiro é chata e trabalhosa: o operador precisa ir dentro de parêntesis, e depois temos que usar o operador ponto 😵💫... pode ficar um pouco confuso...
Porém, com o operador seta podemos acessar os atributos e métodos através de um ponteiro rapidamente:
Ou seja, sempre que você vir ou usar o operador você sabe que está usando um ponteiro para acessar o conteúdo de um objeto.
Podemos reescrever o último segmento do exemplo anterior assim:
Ponteiro
O C++ possui alguns detalhes especiais que podem ajudar na escrita do seu código. Um deles é o ponteiro .
Esse é um ponteiro especial que pode ser usando dentro da classe para se referir aos elementos internos.
Na grande maioria dos casos, o uso do é opcional. Porém, uma situação em que o uso do é obrigatório é quando você tiver um parâmetro de método que tenha o mesmo nome que um atributo da classe. Olha esse exemplo.
Alocação dinâmica de objetos.
Uma coisa que você não pode esquecer é que a principal vantagem trazida pelos ponteiros é a alocação dinâmica de memória. E é claro que o C++ permite a alocação dinâmica de objetos!
O processo é o mesmo da alocação dinâmica de variáveis. Criamos um ponteiro para a classe desejada, e depois usamos o operador para encontrar um lugar disponível na memória. E quando o objeto não for mais necessário poderemos deletá-lo utilizando o
Se for necessário, podemos criar uma array dinâmica de objetos utilizando os operadores e
Ponteiros dentro de uma classe
Você deve se lembrar que ponteiros nada mais são do que um tipo especial de variável que guarda um endereço de memória. Então se você quiser criar um ponteiro que seja membro da classe, então é só declarar este ponteiro dentro da classe:
Os principais usos de ponteiros-membro é possibilitar que a classe utilize variáveis dinamicamente alocadas. Caso você use alocação dinâmica dentro de uma classe, não se esqueça de que vai precisar deletar a memória alocada em algum momento!
Bem, e por hoje é isso pessoal! Vamos agora para os exercícios de fixação!
Operador seta - >
Ponteiro t h i s
Alocação dinâmica de objetos.
Ponteiros dentro de uma classe
Exercícios Resolvidos
Exercício Resolvido #1
Fonte: Elaboração própria
Crie uma classe chamada que tenha um atributo público . Crie um ponteiro que aponte para uma instância dessa classe, e sete o atributo para através do ponteiro. Utilizando o ponteiro imprima o atributo.
Passo 1
Vamos lá, galera.
Essa é uma questão que já dá o passo-a-passo pra gente. Ela quer que a gente crie uma classe, e use um ponteiro pra trabalhar com a classe.
Então vamos começar com o cabeçalho do código:
Passo 2
O passo seguinte é desenvolver a classe . É uma classe simples que contém apenas um único atributo público chamado
Começamos declarando a classe:
Determinamos o escopo como público:
E declaramos o atributo:
E a classe está finalizada.
Passo 3
Belezinha. Vamos agora pra nossa . Para utilizar um ponteiro, vamos precisar criar um objeto da classe e em seguida um ponteiro que aponte para esse objeto.
Primeiro, vamos criar um objeto:
Em seguida, vamos criar um ponteiro para
E fazemos com que o ponteiro aponte para
Passo 4
Show de bola! Com o ponteiro apontando para o objeto, só nos resta acessar o atributo e modificá-lo
E em seguida vamos poder imprimir o número contido em :
E prontinho! Terminamos a questão!
Resposta
Exercício Resolvido #2
Elaboração própria
Crie uma classe com os atributos privado . Crie um método setter e um método para imprimir este atributo usando o ponteiro
Passo 1
Let’s go!
Essa questão quer que a gente exercite o uso do ponteiro . Pra isso a gente vai criar uma classe com um atributo privado e usar o para desenvolver métodos.
Então vamos começar com o cabeçalho do código:
Passo 2
Vamos lá desenvolver a classe. Começamos usando a palavra chave para declarar a classe
Então, dentro do contexto privado, vamos declarar o atributo :
Vamos continuar a construção dessa classe no próximo passo.
Passo 3
Beleza. Temos nossa classe com um atributo privado.
Ainda dentro da nossa classe vamos mudar para o contexto público e construir o nosso setter: uma função que não precisa de retorno e que recebe do usuário o valor do raio.
Usando o ponteiro e o operador podemos acessar o atributo e guardar o valor inserido pelo usuário nesse atributo.
Note que o atributo e o parâmetro têm o mesmo nome. Quando isso acontece, o uso do ponteiro é obrigatório!
No próximo passo a gente vai continuar trabalhando essa classe
Passo 4
Agora temos que desenvolver um método que acesse o valor do atributo e imprima na tela.
Vamos criar o método que não retorna nem recebe nada.
Utilizando o comando vamos imprimir uma mensagem “Raio: ” para o usuário.
Para acessar o valor do atributo podemos usar o ponteiro e o operador seta:
Nesse caso, o uso do ponteiro é opcional.
E prontinho. A classe está pronta.
Resposta
Exercício Resolvido #3
Fonte: elaboração própria
O código abaixo possui erros. Identifique e corrija os erros:
Passo 1
Questões de encontrar erros é sempre bom a gente analisar linha por linha.
Vamos começar observando o código da classe . Aqui temos a declaração de dois atributos do tipo e o desenvolvimento de um método
Note o seguinte: os nomes dos parâmetros do método são iguais aos nomes dos atributos da classe. Quando isso acontece devemos usar o ponteiro para evitar ambiguidades.
Nas linhas 09 e 10 falta utilizar o ponteiro !
Corrigindo o código fica:
Passo 2
Agora vamos olhar a com carinho. Observando o plano geral vemos que na é instanciado um objeto e um ponteiro, o objeto é utilizado para inicializar os atributos e o ponteiro é usado para acessar estes atributos.
Agora vamos olhar linha por linha:
Nas linhas 16 e 17 é declarado um objeto e apontamos o ponteiro para este objeto. Até aqui tudo certo.
Em seguida objeto utiliza a função , porém na linha 19 temos o uso errado do operador seta . Este operador só pode ser utilizado com ponteiros, e não é um ponteiro!
Na linha 19 temos o uso errado do operador seta.
Corrigindo, vamos substituir o operador seta pelo ponto:
Passo 3
Antes de continuar, você precisa lembrar que existem duas formas de usar um ponteiro para acessar um membro do objeto.
A primeira usa os operadores de desreferenciação e ponto
E a segunda forma usa o operador seta
Agora vamos dar uma olhada nos das linhas 21 e 22.
O primeiro tentou utilizar a primeira forma de acessar o atributo. Porém faltaram os parêntesis, e sem eles o código segue na precedência errada. Já o segundo fez uma mistura das duas formas de acessar, porém se a gente apagar o vamos conseguir acessar pela segunda forma.
Na linha 21 falta o uso dos parêntesis, e na linha 22 o uso de é desnecessário.
Corrigindo vamos ter:
E prontinho! Corrigimos todos os erros!
Resposta
Linhas 09 e 10 falta utilizar o ponteiro !
Linha 19 temos o uso errado do operador seta.
Linha 21 falta o uso dos parêntesis
Linha 22 o uso de é desnecessário.
Exercício Resolvido #4
Fonte: elaboração própria
Crie uma classe com os atributos privado . Usando o ponteiro crie um método setter e um método para imprimir o valor da área do círculo.
Em seguida, aloque dinamicamente um objeto da classe , peça pro usuário o valor do raio e imprima a área.
Passo 1
Bora?! Pois vambora!
A questão quer que a gente crie uma classe simples que represente um círculo, e em seguida aloque um objeto dinâmico.
Então vamos começar com o cabeçalho do código. Vamos adicionar a pois será útil para calcular o raio.
Passo 2
Vamos lá desenvolver a classe.
Começamos usando a palavra chave para declarar a classe . Então, dentro do contexto privado, vamos declarar os atributos e :
Mudando para o contexto público vamos construir um setter para alterar o valor do atributo , esse não precisa de retorno (tipo ) e recebe do usuário o valor do raio. Usando o ponteiro e o operador podemos acessar o atributo e guardar o valor inserido pelo usuário nesse atributo.
Note que o atributo e o parâmetro têm o mesmo nome. Quando isso acontece, o uso do ponteiro é obrigatório!
Agora temos que desenvolver um método que calcule a área e imprima o valor na tela.
Vamos criar o método que não retorna nem recebe nada. Esse método acessa o atributo e calcula a área do círculo utilizando a função e guarda o resultado no atributo . Para acessar o valor os atributos e podemos usar o ponteiro e o operador seta:
Em seguida utiliza o comando para imprimir uma mensagem com o valor da área.
Nesse caso, o uso do ponteiro é opcional, pois poderíamos acessar o atributo sem utilizá-lo.
Passo 3
Show de bola. Agora vamos pra parte legal.
Vamos iniciar a . Dentro dela vamos precisar de uma variável que vai receber o valor do raio do usuário. O objetivo da questão é alocar um objeto dinamicamente. Então vamos precisar criar um ponteiro para a classe
O próximo passo é criar o objeto dinâmico. Para isso vamos utilizar o operador para encontrar um endereço de memória disponível onde poderemos alocar dinamicamente um objeto do tipo
Passo 4
Agora é só alegria. O mais difícil já passou.
Vamos usar o e para receber o valor do raio do usuário:
Passo 5
E agora a gente pode usar o ponteiro para acessar o endereço de memória que foi alocado, e através do ponteiro vamos poder trabalhar com o objeto.
Usando o ponteiro e o operador seta podemos utilizar o método para inicializar o valor do raio do círculo
E da mesma forma podemos usar o método
E dessa forma a questão tá praticamente pronta, pois conseguimos alocar um objeto dinâmico e acessá-lo através de um ponteiro.
Passo 6
Mas antes de finalizar a questão, nunca devemos nos esquecer de deletar os objetos criados dinamicamente:
E prontinho! Questão terminada.
Resposta
Exercício Resolvido #5
Elaboração própria
Crie uma classe que receba um valor inteiro do usuário e guarde este valor em uma variável alocada dinamicamente. A alocação dinâmica só deve ocorrer depois que o usuário inserir o valor desejado.
Passo 1
Vamos nessa, galerinha.
A questão tem um enunciado bem direto. Pra gente ter uma variável alocada dinamicamente, nós vamos precisar declarar um ponteiro dentro da nossa classe. Para evitar que o ponteiro seja usado fora da classe, esse ponteiro deverá ser privado.
Vamos precisar de um método que receba o valor do usuário, efetue a alocação dinâmica, e depois guarde o valor recebido dentro do espaço alocado.
Já que o ponteiro é privado, vamos precisar de um método que retorne o valor contido no espaço alocado.
E por último, e muito importante, a gente precisa de uma forma de deletar o espaço alocado quando ele deixar de ser útil. Então vamos precisar de um método que delete o espaço alocado.
Passo 2
Então vamos começar. Primeiro de tudo, vamos iniciar a nossa classe, que vamos chamar de
E dentro do contexto privado vamos declarar um ponteiro para inteiro chamado . Para criar um ponteiro dentro de uma classe é só a gente fazer do mesmo jeito que faria com um ponteiro qualquer:
No código fica:
Esse ponteiro vai ser utilizado no momento de alocar memória dinamicamente.
Vamos continuar a desenvolver a classe no próximo passo.
Passo 3
Agora vamos trabalhar os métodos.
Vamos mudar o contexto para público e começar um método que vai receber um valor inteiro do usuário e guardar esse valor em um espaço dinâmico na memória.
Dentro dessa função vamos começar alocando o espaço do tipo inteiro utilizando o operador
E depois que o espaço estiver alocado, podemos armazenar o valor inserido no espaço. Pra isso, vamos acessar o espaço alocado através do ponteiro:
Passo 4
Lembre-se que o ponteiro que criamos é privado. Então precisamos de um método para acessar o valor armazenado dentro do ponteiro. Vamos então criar um método getter.
Esse getter vai simplesmente retornar o valor contido no ponteiro . Cuidado pra não esquecer do operador, pois é ele que acessa o valor contido no endereço de memória.
Passo 5
A gente tá trabalhando com uma variável alocada dinamicamente com o operador . Então não podemos esquecer de que vamos precisar deletar o espaço alocado em algum momento.
Vamos criar uma função que vai ser responsável por isso. Essa função não precisa retornar nada, e nem precisa receber parâmetros. Porém, quando a função for chamada ela vai aplicar o sobre o ponteiro, para liberar o espaço alocado.
E com isso a classe está pronta, e a questão concluída!
Resposta
Exercício Resolvido #6
Fonte: Adaptado de Prof. Silvana Rosseto – Computação I – Exercícios com ponteiros – Terceira atividade.
Considere a classe abaixo:
Escreva um programa em C++ que receba um valor de entrada e, em seguida:
- Aloque espaço dinamicamente na memória para criar um array de de elementos.
- Preencha o array criado com valores digitados pelo usuário;
- Imprima o array preenchido na tela
- Libere o espaço de memória alocado.
Passo 1
E aí, tranquilidade? Essa questão vai ser um pouco grandinha, mas você vai ver que é tranquila.
Antes de mais nada, observando a classe do enunciado vemos que temos uma variável do tipo . Então vai ser necessário adicionar o cabeçalho
Agora vamos falar um pouco sobre a questão. Ela quer que a gente crie um array dinâmico que armazena objetos da classe , imprima o conteúdo do array dinâmico, e depois apague o array dinâmico.
Pra facilitar a nossa vida, vai ser legal que a gente mexa um pouco na classe e adicione alguns métodos pra facilitar a nossa vida na hora de preencher e imprimir os atributos da classe.
Depois que a classe tiver adaptada, a gente vai pedir o valor de pro usuário, e criar um array dinâmico com o tamanho . E usando loops vamos preencher e imprimir cada um dos objetos armazenados no array
Passo 2
Ok, com o cabeçalho do código já feito, vamos adicionar a classe do enunciado ao nosso programa:
Show. Agora vamos mudar para o contexto público, e dentro dele vamos criar um método que nos ajude na hora de preencher essa classe.
Vamos criar o método , é bem simples, esse método vai usar o e para pedir que o usuário preencha valores, e armazenar os valores inseridos nos atributos adequados. Esse método não precisa receber nenhum parâmetro, e não retornará nada, portanto será :
Ainda no espaço público, vamos criar um outro método que vai nos ajudar a imprimir o conteúdo da classe, chamado que vai imprimir cada um dos atributos junto com uma mensagem adequada:
E pronto. Com isso a gente pode concluir a classe e partir pra
Passo 3
Dentro da vamos começar declarando uma variável e um ponteiro para chamado .
E em seguida perguntamos pro usuário o valor de :
E com o valor de obtido podemos alocar dinamicamente um espaço na memória, com a seguinte sintaxe:
Ou seja, usaremos o operador para alocar espaços do tipo na memória, e guardar o endereço de memória desse espaço no ponteiro :
E assim, a memória foi alocada dinamicamente.
Passo 4
Agora vamos preencher cada uma das pessoas.
Pra isso vamos usar um loop para acessar cada uma das posições do array , e usando o operador ponto vamos poder acessar os métodos contidos dentro do objeto. Ou seja, poderemos usar o método
Iniciamos um loop que vai de até de um em um:
E em cada iteração vamos acessar a posição de e utilizar o método
E finalizamos o loop.
Passo 5
Para imprimir o conteúdo de cada um dos objetos vamos fazer a mesma coisa. Vamos acessar cada um dos elementos do array e utilizar o método
Iniciamos um loop que vai de até de um em um:
E em cada iteração vamos acessar a posição de e utilizar o método
E finalizamos o loop.
Passo 6
Show de bola! O vector dinâmico foi criado, preenchido e impresso!
Por último, mas não menos importante, a gente sempre tem que deletar elementos criados dinamicamente. Então vamos usar o operador para deletar o array dinâmico:
E depois de deletar podemos finalizar o programa com segurança!
Resposta
Exercício Resolvido #7
Adaptado de UFU – FACOM – Professor André Backes – Exercícios de Alocação Dinâmica – Exercício 11
Crie um programa que declare uma classe para o cadastro de alunos.
- Deverão ser armazenados, para cada aluno: matrícula, nome e ano de nascimento.
- Ao início do programa, o usuário deverá informar o número de alunos que serão armazenados
- O programa deverá alocar dinamicamente a quantidade necessária de memória para armazenar os registros dos alunos.
- O programa deverá pedir ao usuário que entre com as informações dos alunos.
- Ao final, mostrar os dados armazenados e liberar a memória alocada.
Passo 1
E aí, vamos lá?
Pra resolver essa questão a gente vai precisar criar uma classe que armazene os dados de um aluno, e depois utilizar um array dinâmico para armazenar informações de alunos
Essa classe vai precisar de três atributos nome, matrícula e ano de nascimento. E pra facilitar nossa vida, vai ser útil criar dois métodos pra ajudar a preencher e imprimir cada um dos objetos.
Depois de criar a classe, vamos perguntar quantos alunos o usuário vai querer cadastrar, e criaremos um vetor dinâmico com a quantidade adequada.
Mas vamos começar pelo cabeçalho do código. Como usaremos um atributo de nome, vai ser útil adicionar o cabeçalho
Passo 2
Ok, com o cabeçalho do código já feito, vamos desenvolver a classe. Vamos precisar de três atributos uma string chamada , um inteiro chamado e outro inteiro chamado . Todos serão privados, por questão de segurança.
Show. Agora vamos mudar para o contexto público, e dentro dele vamos criar um método que nos ajude na hora de preencher essa classe.
Vamos criar o método , que utiliza o e para pedir que o usuário preencha valores, e armazenar os valores inseridos nos atributos adequados.
Depois, vamos criar um método que vai nos ajudar a imprimir o conteúdo da classe, chamado que vai usar o para imprimir cada um dos atributos junto com uma mensagem adequada:
E pronto, a classe está feita
Passo 3
Agora vamos para a , onde vamos começar declarando uma variável que vai ser usada para armazenar a quantidade de alunos que o usuário quer cadastrar. E também um ponteiro que aponta para o tipo e usaremos no processo de alocação dinâmica.
E em seguida perguntamos pro usuário o quantos alunos serão cadastrados:
E com o valor de obtido podemos alocar dinamicamente um espaço na memória, com a seguinte sintaxe:
Ou seja, usaremos o operador para alocar espaços do tipo na memória, e guardar o endereço de memória desse espaço no ponteiro :
E assim, a memória foi alocada dinamicamente.
Passo 4
Agora vamos preencher cada um dos alunos.
Pra isso vamos usar um loop para acessar cada uma das posições do array , e usando o operador ponto vamos poder acessar os métodos contidos dentro do objeto. Ou seja, poderemos usar o método
Iniciamos um loop que vai de até de um em um:
E em cada iteração vamos acessar a posição de e utilizar o método
E finalizamos o loop.
Passo 5
Para imprimir o conteúdo de cada um dos objetos vamos fazer a mesma coisa. Vamos acessar cada um dos elementos do array e utilizar o método
Iniciamos um loop que vai de até de um em um:
E em cada iteração vamos acessar a posição de e utilizar o método
E finalizamos o loop.
Passo 6
E agora o mais difícil já foi: vector dinâmico criado, preenchido e impresso!
Por último, a gente só não pode esquecer de apagar os elementos criados dinamicamente. Então vamos usar o operador para deletar o array dinâmico:
E depois de deletar podemos finalizar o programa com segurança!
Resposta
Exercício Resolvido #8
Elaboração própria
Crie uma classe que tenha como atributo um ponteiro. Essa classe deve ter um método que utiliza este ponteiro para criar um array dinâmico. Se necessário, crie mais métodos e atributos.
Passo 1
E aí, de boas na lagoa? Então vamos lá!
A questão tá pedindo pra gente criar uma classe que utilize array dinâmico. Esse tipo de classe pode ser bem útil quando nosso programa utiliza muitos arrays dinâmicos.
Pra esse tipo de classe funcionar vão ser necessários ao menos dois atributos: o ponteiro que guarda o endereço do array, e um atributo que armazene o tamanho do array.
Além disso, vamos precisar de alguns métodos: um método pra inicializar e preencher o array dinâmico, um método pra gente acessar o conteúdo do array. E claro, se estamos usando array dinâmico, vai ser necessário um método que libere a memória quando o array não for mais necessário, e assim evitaremos vazamento de memória!
Passo 2
Então vamos começar.
Vamos criar uma classe e chamá-la de
E dentro do espaço privado, vamos criar os atributos necessários: o ponteiro que vai armazenar o endereço de memória do array dinâmico, e o atributo que vai armazenar a quantidade de elementos desse array dinâmico.
Nessa questão vamos criar um ponteiro do tipo inteiro. Mas se você quiser, pode criar classes que permitam vetores de qualquer outro tipo!
Passo 3
Agora vamos mudar para o espaço público e vamos criar os métodos.
O primeiro método que vamos criar é um que inicialize o array dinâmico. Vamos chamá-lo de , que será do tipo e vai precisar receber o tamanho do vetor que vai ser alocado.
Dentro desse método vamos alterar o conteúdo do atributo , linha 09. Em seguida vamos usar o operador para alocar dinamicamente um espaço de inteiros com o tamanho inserido pelo usuário, e o endereço de memória vai ser guardado no atributo ponteiro , linha 11.
E após criar o array dinâmico, pedimos pro usuário preencher cada uma das posições, linha 13 a 16.
Passo 4
Ainda no espaço público da nossa classe, vamos precisar de um método que permita a limpeza de memória. Afinal de contas, sempre que trabalhamos com memória alocada dinamicamente, precisamos garantir que a memória seja liberada!
Para isso vamos criar um segundo método chamado que quando chamado utiliza o operador para apagar o conteúdo do endereço de memória apontado por .
Passo 5
Até agora tudo bem. Mas se você pensar bem, vai perceber que nessa classe não existe nenhuma forma de acessar o conteúdo do vetor! Afinal de contas, o ponteiro é um atributo privado.
Então, o que podemos fazer é criar um terceiro método que retorne pra gente o conteúdo de um espaço do vetor.
Vamos chamar esse método de índice. E a função desse método será receber o valor do índice do vetor e retornar o conteúdo daquele índice:
E prontinho! Uma versão básica da classe está criada, e a questão concluída. Mas se quiser se divertir, você pode adicionar mais métodos legais a esta classe 😊