Desafio C++

Classe Livro com múltiplos construtores e validação

Enunciado

Implemente uma classe Livro com membros privados std::string titulo, std::string autor e int ano. Forneça três construtores: um padrão que inicializa com valores vazios/zero, um que recebe título e autor (ano = 0), e um que recebe todos os parâmetros. Adicione um método público exibir() que imprime os dados formatados. Inclua um método setAno(int ano) que só aceita anos maiores ou iguais a 0; caso contrário, mantém o valor anterior. No main, crie três livros usando cada construtor, exiba-os, altere o ano de um deles e exiba novamente.

Requisitos

  • A classe deve ter os membros titulo, autor e ano como private.
  • Devem existir três construtores sobrecarregados: padrão, com título e autor, e com todos os parâmetros.
  • O método setAno deve validar se o ano é >= 0 e ignorar valores negativos.
  • O método exibir deve mostrar os dados no formato Titulo: <titulo>, Autor: <autor>, Ano: <ano>.
  • A saída deve refletir as alterações feitas no main.

Código inicial

#include <iostream>
#include <string>

class Livro {
    // complete aqui
};

int main() {
    // crie três livros e teste
    return 0;
}

Saída esperada

Livro 1: Titulo: Desconhecido, Autor: Desconhecido, Ano: 0
Livro 2: Titulo: 1984, Autor: George Orwell, Ano: 0
Livro 3: Titulo: Dom Casmurro, Autor: Machado de Assis, Ano: 1899
Apos alteracao:
Livro 3: Titulo: Dom Casmurro, Autor: Machado de Assis, Ano: 1900
Ver dica

Use this-> nos construtores e no setAno. O construtor padrão pode chamar outro construtor (delegating constructor) ou usar valores padrão.

Mostrar solução
#include <iostream>
#include <string>

class Livro {
private:
    std::string titulo;
    std::string autor;
    int ano;

public:
    // Construtor padrão
    Livro() : titulo("Desconhecido"), autor("Desconhecido"), ano(0) {}

    // Construtor com título e autor
    Livro(const std::string& titulo, const std::string& autor)
        : titulo(titulo), autor(autor), ano(0) {}

    // Construtor completo
    Livro(const std::string& titulo, const std::string& autor, int ano) {
        this->titulo = titulo;
        this->autor = autor;
        this->ano = ano;
    }

    // Valida e altera o ano
    void setAno(int ano) {
        if (ano >= 0) {
            this->ano = ano;
        }
    }

    // Exibe os dados formatados
    void exibir() const {
        std::cout << "Titulo: " << titulo
                  << ", Autor: " << autor
                  << ", Ano: " << ano << "\n";
    }
};

int main() {
    Livro l1;                                      // construtor padrão
    Livro l2("1984", "George Orwell");            // título e autor
    Livro l3("Dom Casmurro", "Machado de Assis", 1899); // completo

    std::cout << "Livro 1: "; l1.exibir();
    std::cout << "Livro 2: "; l2.exibir();
    std::cout << "Livro 3: "; l3.exibir();

    l3.setAno(1900);  // altera o ano
    std::cout << "Apos alteracao:\n";
    std::cout << "Livro 3: "; l3.exibir();

    return 0;
}

Passo a passo

  1. A classe Livro tem três membros privados: titulo, autor e ano.
  2. O construtor padrão usa lista de inicialização para definir valores padrão.
  3. O construtor com título e autor também usa lista de inicialização e define ano como 0.
  4. O construtor completo usa this-> para atribuir os parâmetros aos membros, pois os nomes coincidem.
  5. O método setAno verifica se o novo ano é >= 0 antes de atribuir; caso contrário, mantém o valor atual.
  6. O método exibir imprime os dados no formato pedido; é const pois não modifica o objeto.
  7. No main, criamos três livros com os diferentes construtores e chamamos exibir().
  8. Alteramos o ano do terceiro livro com setAno(1900) e exibimos novamente.

Por que funciona

A sobrecarga de construtores permite criar objetos com diferentes níveis de informação. O uso de this-> no construtor completo e no setAno resolve a ambiguidade entre parâmetros e membros. A validação em setAno garante que o estado do objeto permaneça consistente, um princípio do encapsulamento.

Erros comuns

  • Não validar em setAno: aceitar anos negativos quebra a lógica do domínio.
    if (ano >= 0) { this->ano = ano; } é essencial.
  • Esquecer this-> no construtor completo: titulo = titulo; não altera o membro, pois o parâmetro esconde o membro.
  • Não marcar exibir() como const: impede chamar em objetos constantes e não expressa a intenção de não modificar.
  • Usar std::string sem incluir <string>: erro de compilação. Sempre inclua o cabeçalho necessário.

Outra forma de resolver

Usar argumentos padrão em um único construtor:

Livro(const std::string& titulo = "Desconhecido",
      const std::string& autor = "Desconhecido",
      int ano = 0) : titulo(titulo), autor(autor), ano(ano) {}

Isso reduz a repetição, mas perde a clareza de ter construtores separados. Prefira a sobrecarga quando os construtores tiverem comportamentos distintos.

Saída esperada

Livro 1: Titulo: Desconhecido, Autor: Desconhecido, Ano: 0
Livro 2: Titulo: 1984, Autor: George Orwell, Ano: 0
Livro 3: Titulo: Dom Casmurro, Autor: Machado de Assis, Ano: 1899
Apos alteracao:
Livro 3: Titulo: Dom Casmurro, Autor: Machado de Assis, Ano: 1900