# 17.1 - Classes

Embora o C ++ forneça vários tipos de dados fundamentais (por exemplo, char, int, long, float, double, etc ...) que geralmente são suficientes para resolver problemas relativamente simples, pode ser difícil resolver problemas complexos usando apenas esses tipos. Um dos recursos mais úteis do C ++ é a capacidade de definir seus próprios tipos de dados que melhor correspondem ao problema que está sendo resolvido. Você já viu como tipos e estruturas enumerados podem ser usados para criar seus próprios tipos de dados personalizados.

No mundo da programação orientada a objetos, geralmente queremos que nossos tipos não apenas mantenham dados, mas também forneçam funções que funcionem com os dados. Em C ++, isso geralmente é feito através da palavra-chave da classe. O uso da palavra-chave class define um novo tipo definido pelo usuário chamado class.

No C ++, classes e estruturas são essencialmente as mesmas. De fato, a seguinte estrutura e classe são efetivamente idênticas:














struct FuncionarioStruct
{
    std::string m_nome;
    int m_idade;
};
 
class FuncionarioClasse
{
public:
    std::string m_nome;
    int m_idade;
};

# Keyword public, protected e private

Note a utilização do public, quer dizer que tanto membros da classe(ou seja, funções que estão dentro da classe) e membros externos podem acessar esta variável.

Por exemplo:













struct FuncionarioStruct
{
    std::string m_nome;
    int m_idade;
};

int main() 
{
  FuncionarioStruct f;
  f.m_nome = "João";
}

É possivel modificar diretamente o nome pois struct's não possuem keyword de acesso, e por padrão utilizam public

# Setters e Getters

Então para acessar uma variável privada, precisamos de funções na classe para alterar ou retornar esses valores,dando o exemplo:














































#include <iostream>
#include <memory>

// Requer flag de C++17

namespace FUNCIONARIO // Namespace que irá conter a classe Atendente
{
class Atendente
{
private: // Keyword private
    std::string m_nome;

public:                          // Keyword public
    Atendente(std::string nNome) // Construtor da classe, recebendo um parâmetro nNome
    {
        this->m_nome = nNome;
    }

    ~Atendente() // Destrutor da Classe
    {
    }

    void setNome(std::string nNome) // Setter do nome
    {
        this->m_nome = nNome;
    }

    const std::string getNome() const // Getter do nome
    {
        return this->m_nome;
    }
};
} // namespace FUNCIONARIO

auto main() -> int
{
    auto ul = std::make_unique<FUNCIONARIO::Atendente>("Jose"); // Instanciação da classe Atendente

    std::cout << ul->getNome() << std::endl; // Exibe Jose

    ul->setNome("Claudio"); // Seta o m_nome Claudio

    std::cout << ul->getNome() << std::endl; // Exibe Claudio
}

Demos um exemplo de utilização de namespace, agrupando outras variantes de funcionarios possíveis.

Mas, várias classes diferentes de tipos de funcionário terão atributos parecidos e terá uma repetição de código.

Para isso, podemos herdar classes para evitar repetição.

A keyword protected serve para esse caso, pois classes filhas, ou seja, que herdam de uma classe mãe podem acessar seus métodos, mas ainda sim conteúdos de fora não podem acessar seus métodos.

Exemplo:







































































class Funcionario
{
protected: // Keyword private
    std::string m_nome;

public:                            // Keyword public
    Funcionario(std::string nNome) // Construtor da classe, recebendo um parâmetro nNome
    {
        this->m_nome = nNome;
    }

    Funcionario()
    {
        this->m_nome = "";
    }

    ~Funcionario() // Destrutor da Classe
    {
    }

    void setNome(std::string nNome) // Setter do nome
    {
        this->m_nome = nNome;
    }

    const std::string getNome() const // Getter do nome
    {
        return this->m_nome;
    }
};
class Atendente : public Funcionario // Herdando funcionario
{
private: // Keyword private
    std::string m_turno;

public:                                              // Keyword public
    Atendente(std::string nNome, std::string nTurno) // Construtor da classe, recebendo um parâmetro nNome
    {
        this->m_nome = nNome; // Se m_nome fosse privado, teria que utilizar typedef
        this->m_turno = m_turno;
    }

    ~Atendente() // Destrutor da Classe
    {
    }

    void setTurno(std::string nTurno) // Setter do turno
    {
        this->m_turno = nTurno;
    }

    const std::string getTurno() const // Getter do turno
    {
        return this->m_turno;
    }
}; // namespace FUNCIONARIO

auto main() -> int
{
    auto ul = std::make_unique<Atendente>("Jose", "Tarde");

    std::cout << ul->getNome() << std::endl; // Exibe Jose

    ul->setTurno("Noite"); // Seta o turno Noite

    std::cout << ul->getTurno() << std::endl; // Exibe Noite

    return EXIT_SUCCESS;
}

Getters e Setters possuem padronização, da mesma forma mostrado anteriormente:



















class Date
{
private:
    int m_month;
    int m_day;
    int m_year;
 
public:
    int getMonth() { return m_month; } // getter do mes
    const void setMonth(int month) const { m_month = month; } // setter do mes
 
    int getDay() { return m_day; } // getter do dia
    const void setDay(int day) const { m_day = day; } // setter do dia
 
    int getYear() { return m_year; } // getter do ano
    const void setYear(int year) const { m_year = year; } // setter do ano
};

Os getters devem fornecer acesso "somente leitura" aos dados. Portanto, a melhor prática é que eles retornem por valor ou referência const (não por referência não const). Um getter que retorna uma referência não-const permitiria ao chamador modificar o objeto real que está sendo referenciado, o que viola a natureza somente leitura do getter (e viola o encapsulamento).

Prática recomendada: Getters devem retornar por valor ou referência const