-
Notifications
You must be signed in to change notification settings - Fork 0
Module 05
(Modulo 05)
Uma classe aninhada (nested class) é uma classe que é definida dentro do escopo de outra classe. Essas classes são úteis para organizar e agrupar logicamente o código relacionado, especialmente quando a classe aninhada é fortemente associada à classe externa. A classe aninhada pode acessar membros privados da classe que a contém, mas o contrário não é verdade a menos que sejam feitas provisões específicas para isso.
Aqui está um exemplo básico para ilustrar o conceito de classes aninhadas:
#include <iostream>
class Outer {
public:
Outer(int val) : value(val) {}
void show() const { std::cout << "Outer value: " << value << std::endl; }
class Inner {
public:
Inner(int val) : innerValue(val) {}
void show() const { std::cout << "Inner value: " << innerValue << std::endl; }
private:
int innerValue;
};
private:
int value;
};
int main() {
Outer outer(10);
outer.show();
Outer::Inner inner(20);
inner.show();
return 0;
}
-
Definição da Classe Aninhada:
- A classe
Inner
é definida dentro da classeOuter
. -
Inner
é uma classe pública deOuter
, o que significa que pode ser acessada de fora da classeOuter
.
- A classe
-
Criação de Objetos:
- Um objeto da classe
Outer
é criado usando o construtorOuter
. - Um objeto da classe
Inner
é criado usandoOuter::Inner
, indicando queInner
está dentro do escopo deOuter
.
- Um objeto da classe
-
Acesso aos Membros:
- A classe
Inner
tem seu próprio conjunto de membros, independente da classeOuter
. -
Inner
pode acessar os membros privados da classeOuter
se necessário, mas nesse exemplo específico, não há tal acesso.
- A classe
Uma classe aninhada pode acessar membros privados da classe externa diretamente. Aqui está um exemplo:
#include <iostream>
class Outer {
public:
Outer(int val) : value(val) {}
class Inner {
public:
void show(const Outer& outer) const { std::cout << "Accessing Outer value: " << outer.value << std::endl; }
};
private:
int value;
};
int main() {
Outer outer(10);
Outer::Inner inner;
inner.show(outer);
return 0;
}
Neste exemplo, a classe Inner
acessa diretamente o membro privado value
da instância da classe Outer
passada como argumento.
Classes aninhadas são úteis em várias situações:
-
Encapsulamento de Implementação:
- A classe aninhada pode ser usada para ocultar detalhes de implementação que não devem ser expostos fora da classe externa.
-
Organização de Código:
- Mantém o código relacionado logicamente agrupado, o que pode tornar o código mais limpo e fácil de entender.
-
Acesso a Membros Privados:
- Facilita o acesso a membros privados da classe externa sem a necessidade de friend declarations.
Classes aninhadas em C++ são uma poderosa ferramenta para organizar e encapsular o código, mantendo o acesso aos membros privados quando necessário. Elas são particularmente úteis quando há uma relação lógica forte entre as duas classes, permitindo um design mais limpo e coeso.
Exceções em C++98 são uma maneira de lidar com erros ou condições excepcionais que ocorrem durante a execução de um programa. Elas permitem que um programa lide com problemas de forma controlada e organizada, separando a lógica de tratamento de erros da lógica principal do programa. O mecanismo de exceções envolve três componentes principais: lançamento de exceções, captura de exceções e tratamento de exceções.
-
Lançamento de Exceções (Throwing Exceptions):
- Quando uma condição de erro é detectada, uma exceção é lançada usando a palavra-chave
throw
.
- Quando uma condição de erro é detectada, uma exceção é lançada usando a palavra-chave
-
Captura de Exceções (Catching Exceptions):
- As exceções lançadas são capturadas por um bloco
catch
correspondente que é capaz de tratar o tipo específico de exceção lançada.
- As exceções lançadas são capturadas por um bloco
-
Tratamento de Exceções (Handling Exceptions):
- Dentro do bloco
catch
, o programa pode tentar corrigir o erro, limpar recursos ou tomar outras ações apropriadas.
- Dentro do bloco
Aqui está um exemplo simples que demonstra como lançar, capturar e tratar exceções em C++98:
#include <iostream>
#include <stdexcept> // Para std::runtime_error e std::out_of_range
void functionThatThrows() {
throw std::runtime_error("An error occurred");
}
void anotherFunctionThatThrows() {
throw std::out_of_range("Out of range error");
}
int main() {
try {
functionThatThrows();
}
catch (const std::runtime_error& e) {
std::cerr << "Caught a runtime_error: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Caught an unknown exception" << std::endl;
}
try {
anotherFunctionThatThrows();
}
catch (const std::out_of_range& e) {
std::cerr << "Caught an out_of_range exception: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Caught an unknown exception" << std::endl;
}
return 0;
}
-
Lançamento de Exceções:
- A função
functionThatThrows
lança uma exceção do tipostd::runtime_error
usandothrow
. - A função
anotherFunctionThatThrows
lança uma exceção do tipostd::out_of_range
.
- A função
-
Bloco try:
- O código que pode lançar uma exceção é colocado dentro de um bloco
try
.
- O código que pode lançar uma exceção é colocado dentro de um bloco
-
Blocos catch:
- Quando uma exceção é lançada, o controle é transferido para o primeiro bloco
catch
que pode manipular o tipo específico da exceção. - O bloco
catch (const std::runtime_error& e)
captura exceções do tipostd::runtime_error
. - O bloco
catch (const std::out_of_range& e)
captura exceções do tipostd::out_of_range
. - O bloco
catch (...)
é um bloco de captura geral que pode capturar qualquer tipo de exceção.
- Quando uma exceção é lançada, o controle é transferido para o primeiro bloco
-
Tratamento da Exceção:
- Dentro do bloco
catch
, usamosstd::cerr
para imprimir uma mensagem de erro, indicando que uma exceção foi capturada.
- Dentro do bloco
-
Separação da Lógica de Erro:
- As exceções permitem separar a lógica de tratamento de erros do código principal, tornando o código mais limpo e legível.
-
Gerenciamento de Recursos:
- Com exceções, você pode garantir que recursos (como memória, arquivos ou conexões de rede) sejam liberados adequadamente usando técnicas como RAII (Resource Acquisition Is Initialization).
-
Propagação de Erros:
- As exceções permitem que os erros sejam propagados para níveis superiores do programa, onde podem ser tratados de forma mais apropriada.
-
Desempenho:
- O uso de exceções pode introduzir alguma sobrecarga de desempenho. No entanto, essa sobrecarga geralmente é justificada pela melhoria na robustez e na manutenibilidade do código.
-
Exceções Personalizadas:
- Em C++, você pode definir suas próprias classes de exceção para representar diferentes tipos de erros específicos do seu aplicativo.
Exemplo de uma exceção personalizada:
#include <iostream>
#include <exception>
class MyException : public std::exception {
public:
const char* what() const throw() {
return "My custom exception";
}
};
void functionThatThrows() {
throw MyException();
}
int main() {
try {
functionThatThrows();
}
catch (const MyException& e) {
std::cerr << "Caught a MyException: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Caught an unknown exception" << std::endl;
}
return 0;
}
Neste exemplo, a classe MyException
é uma exceção personalizada que herda de std::exception
e sobrescreve o método what()
para fornecer uma mensagem de erro personalizada.
Exceções são uma ferramenta poderosa em C++98 para tratar erros de forma robusta e estruturada. Elas permitem que o código principal permaneça limpo e focado em sua lógica principal, enquanto o tratamento de erros é delegado a blocos específicos de código. Além disso, exceções ajudam a garantir que os recursos sejam gerenciados adequadamente, evitando vazamentos e outros problemas relacionados.
Em C++, a biblioteca padrão oferece um conjunto de classes de exceção para tratar diferentes tipos de erros que podem ocorrer durante a execução do programa. Essas exceções são organizadas em duas categorias principais: erros lógicos (logic errors) e erros em tempo de execução (runtime errors). A maneira como essas exceções são lançadas e tratadas é similar, mas elas representam diferentes tipos de problemas. Vamos analisar como elas funcionam e como o tratamento delas pode ser feito.
stdexcept é um cabeçalho que fornece várias classes de exceção padrão, como std::runtime_error
, std::out_of_range
, std::invalid_argument
, entre outras. Essas classes são úteis para representar diferentes tipos de erros e fornecer informações detalhadas sobre o que deu errado.*
Erros lógicos representam falhas que normalmente indicam um erro de programação, ou seja, situações onde o código está incorreto, mas o erro pode ser detectado durante a execução. Essas exceções pertencem à classe base std::logic_error
.
-
logic_error
: Classe base para todos os erros lógicos. Pode ser lançada diretamente ou através de seus subtipos. -
domain_error
: Usada quando uma função é chamada com um valor que não pertence ao domínio permitido.- Exemplo: calcular a raiz quadrada de um número negativo.
-
invalid_argument
: Lançada quando um argumento inválido é passado para uma função.- Exemplo: passar uma string vazia onde uma string válida é esperada.
-
length_error
: Usada quando uma operação excede o limite de tamanho permitido (como ao tentar alocar mais memória do que o disponível). -
out_of_range
: Usada para acessar um elemento fora dos limites de um contêiner, como um array ou vector.- Exemplo: acessar o índice 10 de um array que tem apenas 5 elementos.
Erros de tempo de execução representam condições anômalas que ocorrem enquanto o programa está em execução. Eles são detectados somente durante a execução e não necessariamente indicam um erro de programação. Esses erros pertencem à classe base std::runtime_error
.
-
runtime_error
: Classe base para todos os erros em tempo de execução. -
range_error
: Usada quando um valor ultrapassa o intervalo válido para uma operação.- Exemplo: uma função que retorna um número fora do intervalo permitido por algum cálculo.
-
overflow_error
: Lançada quando ocorre um overflow aritmético.- Exemplo: um número inteiro positivo que excede o valor máximo representável pelo tipo.
-
underflow_error
: Lançada quando ocorre um underflow aritmético.- Exemplo: o inverso de um
overflow
, como quando um número fica abaixo do valor mínimo representável.
- Exemplo: o inverso de um
Todas essas exceções seguem o mesmo mecanismo de tratamento de exceções em C++, mas cada tipo de exceção é projetado para representar um erro específico.
Para lançar qualquer uma dessas exceções, usa-se a palavra-chave throw
. Por exemplo:
throw std::out_of_range("Index is out of range");
O tratamento de exceções é feito com os blocos try
, catch
e throw
. Uma exceção é lançada dentro de um bloco try
, e um bloco catch
correspondente captura e trata o erro. Você pode capturar a exceção como uma referência a um objeto da classe base (std::exception
) ou usar capturas mais específicas.
Exemplo de tratamento de exceções:
#include <iostream>
#include <stdexcept> // Para as classes de exceção padrão
int main() {
try {
throw std::out_of_range("Index is out of range");
}
catch (const std::out_of_range& e) {
std::cerr << "Out-of-range error: " << e.what() << std::endl;
}
catch (const std::exception& e) {
std::cerr << "General error: " << e.what() << std::endl;
}
return 0;
}
O comportamento dessas exceções no tratamento é essencialmente o mesmo — elas são capturadas e tratadas em blocos catch
. O que muda é o tipo de exceção lançada e a mensagem associada. Cada exceção é projetada para representar um tipo específico de erro, permitindo que o código seja mais expressivo e específico sobre o que deu errado.
-
Classes de Erros Lógicos: Representam erros de programação (como
std::out_of_range
,std::invalid_argument
), que podem ser detectados durante o desenvolvimento. -
Classes de Erros em Tempo de Execução: Representam problemas que surgem durante a execução do programa (como
std::overflow_error
,std::underflow_error
). -
Mecanismo de Tratamento: O mecanismo de tratamento de exceções (
try
-catch
) é o mesmo para todos os tipos de exceções, mas o tipo específico de exceção fornece informações mais detalhadas sobre o erro.
Cada tipo de exceção define um erro específico, mas o mecanismo para lidar com elas é o mesmo, e as mensagens de erro (e.what()
) ajudam a identificar o que causou a exceção.