- Operadores fundamentais: & e *
Em C++, o operador & retorna o endereço de uma variável, enquanto o operador * pode declarar um ponteiro ou acessar o valor apontado por ele.
#include <iostream>
int main()
{
int x = 10, y = 20;
int* ptrX = &x;
int* ptrY = &y;
std::cout << "Endereco de x: " << ptrX << "\n";
std::cout << "Valor de x: " << *ptrX << "\n";
return 0;
}
- Ponteiros e referências
Apesar de ambos permitirem acessar um objeto indiretamente, possuem semânticas distintas:
- Ponteiro: variável que armazena um endereço. Pode ser reatribuído, aceitar
nullptre ter múltiplos níveis. - Referência: apelido para uma variável já existente. Deve ser inicializada e nunca muda de objeto vinculado.
int valor = 42;
int* p = &valor; // ponteiro
int& r = valor; // referência: apelido de valor
std::cout << *p; // 42
std::cout << r; // 42
Outras diferenças importantes:
sizeof(r)retorna o tamanho do objeto referenciado;sizeof(p)retorna o tamanho do próprio ponteiro.- O operador
++em um ponteiro avança para o próximo elemento do tipo apontado; em uma referência incrementa o valor do objeto. - Ponteiros admitem várias qualificações
const(const int*,int* const); referências não podem ser reseatadas, apenas vinculadas a objetosconst.
structversusclass
Em C++, struct e class são quase idênticos, mas existem duas diferenças principais:
- A visibilidade padrão em
structépublic; emclass,private. - Em tepmlates, o parâmetro de tipo deve ser declarado com
classoutypename, nãostruct.
Uma struct pode conter um ponteiro para seu próprio tipo, mas não uma instância direta, pois o tipo ainda está incompleto naquele ponto.
Quando usar cada um:
struct: agregados leves que basicamente armazenam dados, como coordenadas, retângulos ou registros simples.class: entidades com lógica complexa, invariantes, encapsulamento e hierarquias de herança.
- Passagem e retorno de objetos
Passar um objeto diretamente por valor copia todos os seus membros, o que pode ser custoso e desnecessário:
void func(Objeto obj); // copia: evitar
void func(Objeto* obj); // ponteiro: pode ser nulo
void func(Objeto& obj); // referência: não nulo
void func(const Objeto& obj); // referência const: leitura eficiente
Ao retornar um objeto, retornar referência ou ponteiro evita construções de cópia, desde que o objeto retornado continue existindo fora da função. Nunca retorne referência para variável local.
Para impedir cópias indesejadas, torne o construtor de cópia privado (em C++11 e posteriores, use = delete).
- Atribuição, criação e exemplo prático
A atribuição entre objetos copia o estado dos membros de dados; funções-membro não são copiadas. Se a classe gerencia memória dinâmica, deve-se implementar o construtor de cópia e o operador de atribuição para evitar cópias rasas.
Podemos criar objetos na pilha ou no heap:
Objeto o; // pilha
Objeto* p = new Objeto(); // heap: lembre-se de delete
Exemplo ilustrando ponteiro para objeto:
#include <iostream>
class Ponto {
public:
int x;
int y;
};
class Caixa {
public:
Ponto* ref;
void vincula(Ponto& p) {
ref = &p;
p.x = 5;
p.y = 9;
std::cout << ref->x << "\n";
std::cout << ref->y << "\n";
}
};
int main() {
Ponto* p = new Ponto();
p->x = 1;
p->y = 2;
Caixa* c = new Caixa();
c->vincula(*p);
delete p;
delete c;
return 0;
}