Funções de Membro Const
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 29 de 104.
Você viu a palavra-chave const em métodos getter na lição anterior. Mas o que exatamente significa quando const aparece após a lista de parâmetros de uma função? Uma função membro const promete não modificar nenhuma variável membro do objeto.
class Rectangle {
int width;
int height;
public:
Rectangle(int w, int h) : width(w), height(h) {}
int getArea() const { // função membro const
return width * height; // A leitura de membros é permitida
}
void setWidth(int w) { // Não-const - modifica o objeto
width = w;
}
};O const após a lista de parâmetros diz ao compilador: "Esta função não alterará o estado do objeto." Se você tentar modificar uma variável de membro dentro de uma função const, o compilador produzirá um erro.
Isso se torna essencial ao trabalhar com objetos const ou referências const. Um objeto const só pode chamar funções membro const:
void printArea(const Rectangle& rect) {
std::cout << rect.getArea(); // OK - getArea() é const
// rect.setWidth(10); // ERRO - setWidth() não é const
}Marcar funções como const quando elas não modificam o objeto é uma boa prática. Isso documenta sua intenção, permite que a função funcione com objetos const e ajuda o compilador a detectar modificações acidentais. Qualquer função membro que apenas lê dados deve ser marcada como const.
Desafio
FácilVamos construir um conversor de temperatura que demonstra quando e por que usar funções membros const. Você criará uma classe onde alguns métodos apenas leem dados (e devem ser const), enquanto outros modificam o estado do objeto.
Você criará dois arquivos para organizar seu código:
Temperature.h: Defina uma classeTemperatureque armazena um valor de temperatura e fornece várias maneiras de lê-lo e modificá-lo. Sua classe deve ter:- Um membro privado
celsius(double) para armazenar a temperatura - Um construtor que recebe um valor inicial em Celsius
- Um método
getCelsius()que retorna o valor armazenado — este deve ser const, pois apenas lê dados - Um método
getFahrenheit()que calcula e retorna a temperatura em Fahrenheit usando a fórmulacelsius * 9.0 / 5.0 + 32.0— também const, pois não modifica nada - Um método
getKelvin()que retorna a temperatura em Kelvin usandocelsius + 273.15— const também - Um método
setCelsius(double value)que atualiza a temperatura armazenada — este não pode ser const, pois modifica o objeto - Um método
adjustBy(double delta)que adiciona o delta à temperatura atual — também não-const
- Um membro privado
main.cpp: Demonstre como as funções membros const funcionam com objetos regulares e const. Leia um valor de temperatura inicial da entrada e, em seguida:- Crie um objeto
Temperaturecom o valor de entrada - Imprima
"Initial: <celsius>C = <fahrenheit>F = <kelvin>K" - Ajuste a temperatura em
10.0graus - Imprima
"After adjustment: <celsius>C" - Crie uma função auxiliar
void printReadings(const Temperature& temp)que recebe uma referência const e imprime"Reading: <celsius>C, <fahrenheit>F"— esta função só pode chamar métodos const em temp - Chame
printReadings()com seu objeto de temperatura - Defina a temperatura como
0.0(ponto de congelamento) - Imprima
"Freezing point: <celsius>C = <fahrenheit>F"
- Crie um objeto
Formate todos os valores de temperatura com uma casa decimal usando std::fixed e std::setprecision(1) de <iomanip>.
A ideia principal aqui é que printReadings() recebe uma referência const, portanto, só pode chamar métodos marcados como const. É por isso que marcar corretamente seus métodos getter como const é importante — isso permite que eles funcionem em contextos onde o objeto não pode ser modificado.
Folha de consulta
Uma função membro const promete não modificar nenhuma variável membro do objeto. A palavra-chave const é colocada após a lista de parâmetros da função:
class Rectangle {
int width;
int height;
public:
int getArea() const { // função membro const
return width * height; // Ler membros é permitido
}
void setWidth(int w) { // Não-const - modifica o objeto
width = w;
}
};Funções membro const podem apenas ler variáveis membro, não modificá-las. Se você tentar modificar uma variável membro dentro de uma função const, o compilador produzirá um erro.
Um objeto const ou uma referência const só pode chamar funções membro const:
void printArea(const Rectangle& rect) {
std::cout << rect.getArea(); // OK - getArea() é const
// rect.setWidth(10); // ERRO - setWidth() não é const
}Marque funções como const quando elas não modificarem o objeto. Isso documenta sua intenção, permite que a função funcione com objetos const e ajuda o compilador a capturar modificações acidentais. Qualquer função membro que apenas lê dados deve ser marcada como const.
Experimente você mesmo
#include <iostream>
#include <iomanip>
#include "Temperature.h"
using namespace std;
// TODO: Implementar os métodos da classe Temperature aqui
// Construtor
Temperature::Temperature(double initialCelsius) {
// TODO: Inicializar celsius
}
// TODO: Implementar getCelsius() como const
// TODO: Implementar getFahrenheit() como const
// TODO: Implementar getKelvin() como const
// TODO: Implementar setCelsius(double value)
// TODO: Implementar adjustBy(double delta)
// TODO: Criar uma função auxiliar printReadings que recebe um const Temperature&
// e imprime "Reading: <celsius>C, <fahrenheit>F"
// Note: Esta função só pode chamar métodos const em temp!
int main() {
double initialTemp;
cin >> initialTemp;
// Configurar a formatação da saída
cout << fixed << setprecision(1);
// TODO: Criar um objeto Temperature com o valor de entrada
// TODO: Imprimir "Initial: <celsius>C = <fahrenheit>F = <kelvin>K"
// TODO: Ajustar a temperatura em 10.0 graus
// TODO: Imprimir "After adjustment: <celsius>C"
// TODO: Chamar printReadings() com o seu objeto de temperatura
// TODO: Definir a temperatura para 0.0 (ponto de congelamento)
// TODO: Imprimir "Freezing point: <celsius>C = <fahrenheit>F"
return 0;
}
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico