No começo, trabalharemos com a classe no mesmo arquivo.
Para declarar a classe (lembrando que todo nome de classe começa com maiúscula), e no C++ tem que ter ponto e vírgula após o fechamento das chaves:
class Aviao {
public:
// Atributos:
int velocidade;
int velMax;
string tipo;
// Métodos, construídos fora da classe:
void ini(int tp);
private:
};
void Aviao::ini(int tp) { // Referência a classe e o nome do método.
if(tp == 1) {
this->velMax = 800;
this->tipo = "Jato";
}
else if(tp == 2) {
this->velMax = 350;
this->tipo = "Monomotor";
}
else if(tp == 3) {
this->velMax = 180;
this->tipo = "Planador";
}
}
PS: Note que os métodos são criados fora da classe, no entanto, eles são indicados dentro dela, onde também são definidos a visibilidade os mesmos. As inicializações de atributos são as únicas coisas feitas dentro da classe, caso existam (e não sejam estáticos) E o this vai ser substituído pelo nome do objeto. Ele verifica um atributo dentro de um método da própria classe e será substituído pela classe chamadora. O this não é necessário ser usado no C++, mas é bom mantermos o hábito de usar ele.
É permitido criar métodos dentro das classes, mas esse método não é muito usado em C++, nesse caso, ficaria assim:
class Aviao {
public:
int velocidade;
int velMax;
string tipo;
void ini(int tp) {
if(tp == 1) {
this->velMax = 800;
this->tipo = "Jato";
}
else if(tp == 2) {
this->velMax = 350;
this->tipo = "Monomotor";
}
else if(tp == 3) {
this->velMax = 180;
this->tipo = "Planador";
}
}
private:
};
No método principal, basta chamar assim:
int main() {
Aviao *av1 = new Aviao();
av1->ini(3);
cout << av1->velMax;
delete av1;
return 0;
}
PS: Note que ao criar um novo objeto, temos que colocar o asterisco, que é o ponteiro que indica o endereço de memória do objeto. Sempre que criamos um objeto usando new, ele cria uma alocação de memória, e por isso devemos chamar pelo ponteiro. Sempre delete o ponteiro com o delete.
Quando criamos uma classe, temos mais trabalho para fazê-la, mas depois que ela está pronta, podemos criar quantos objetos precisarmos vindos dessa mesma classe, e o programa principal fica mais simples, menor e mais natural. Os objetos criados dessa mesma classe são independentes entre si e o status de um não interfere no outro. Essa é uma das vantagens da orientação a objetos.
Caso queira criar objetos em Array, pode fazer algo do tipo:
int main() {
Aviao *av[3]; // Colocar quantidade de posições desejadas
// No caso, terá três posições contadas a partir do 0.
av[0] = new Aviao();
av[1] = new Aviao();
av[2] = new Aviao();
av[0]->ini(1);
av[1]->ini(2);
av[2]->ini(3);
cout << av[0]->velMax << endl;
cout << av[1]->velMax << endl;
cout << av[2]->velMax << endl;
delete *av; // Destruindo array com ponteiro
return 0;
}
No caso de listas, vector e outros contâiners, usamos o ponteiro com o nome da classe dentro das tags do mesmo, por exemplo:
vector<Aviao*> av;
av.push_back(new Aviao());
av.push_back(new Aviao());
av.push_back(new Aviao());
av[0]->ini(1);
av[1]->ini(2);
av[2]->ini(3);
Código completo abaixo:
#include <iostream>
using namespace std;
class Aviao {
public:
// Atributos:
int velocidade;
int velMax;
string tipo;
// Métodos, construídos fora da classe:
void ini(int tp);
private:
};
void Aviao::ini(int tp) { // Referência a classe e o nome do método.
if(tp == 1) {
this->velMax = 800;
this->tipo = "Jato";
}
else if(tp == 2) {
this->velMax = 350;
this->tipo = "Monomotor";
}
else if(tp == 3) {
this->velMax = 180;
this->tipo = "Planador";
}
}
int main() {
Aviao *av[3]; // Não esqueça do ponteiro
av[0] = new Aviao();
av[1] = new Aviao();
av[2] = new Aviao();
av[0]->ini(1);
av[1]->ini(2);
av[2]->ini(3);
cout << av[0]->velMax << endl;
cout << av[1]->velMax << endl;
cout << av[2]->velMax << endl;
delete *av;
return 0;
}
PS: Em C++, a seta é usada para atributos e métodos de objetos criados com ponteiro, que usa o new, quando é apenas uma nova atribuição com um objeto existente, usamos o ponto. Veja abaixo como seria a criação de uma instância sem new (apesar de funcionar, não é recomendada por não usar alocação de memória):
Aviao av; // Nesse caso usa sem ponteiro
av.ini(1); // Usa pontos por não ser criado com new, também não usa delete
Isso ocorre porque, ao criar uma variável de um objeto, automaticamente ele é atribuído à classe especificada, mesmo sem inicializar, em linguagens como Java e C# não é possível fazer assim, exigindo a instanciação do objeto com o new.
Caso a classe tenha algum parâmetro no construtor, coloque os parênteses na variável do objeto e seus parâmetros, caso não tenha nenhum não coloque parênteses.
Lembrando de que, quando utilizamos ponteiros e new, a variável do objeto sempre ocupará um espaço fixo na memória (8 bytes), por ele armazenar somente a referência apontando para a instância criada com new. Quando criamos o objeto diretamente sem o new, ele ocupará mais espaço, dependendo da quantidade de atributos e métodos contidos na classe, por exemplo:
Aviao av;
Aviao *av2 = new Aviao();
cout << sizeof(av) << endl;
cout << sizeof(av2) << endl;
delete av2;
Caso queira retornar o nome da classe em C++, use o método typeid(*this).name()
no objeto (não esqueça de incluir no cabeçalho <typeinfo>
).
Quando fizermos uma agregação entre diferentes objetos, como as passagens de parâmetros, atributos ou retornos com objetos e classes, também é necessário usar ponteiros nos objetos, tanto na implementação quanto na declaração, por exemplo:
class Aeroporto {
public:
Aviao *avi; // Não esqueça do ponteiro, pode ser preciso retirá-lo em alguns casos de chamar componentes através do outro objeto.
const Aviao *getAvi(); // Aqui também tem ponteiro
void setAvi(Aviao *avi); // Não esqueça do ponteiro
};
const Aviao *Aeroporto::getAvi() { // Não esqueça do ponteiro
return this->avi;
}
void Aeroporto::setAvi(Aviao *avi) { // Não esqueça do ponteiro
this->avi = avi;
}
PS: Nos métodos setter com outros objetos, se o parâmetro tem ponteiro, basta passar o objeto sem o asterisco. Caso o parâmetro não tenha ponteiro, será necessário passar o objeto com o símbolo &
.
Ou seja, sempre que declararmos, inicializarmos ou retornar objetos, se utilizam os ponteiros neles. Se for inicializar ele, use o new NomeDaClasse()
normalmente. Mas inicialização de atributos não são muito usados, a não ser que sejam constantes (inicializados dentro da classe) ou estáticos (cuja inicialização ocorre fora da classe no arquivo de implementação).
Para usar métodos ou atributos de objetos agregados na classe principal, fazemos assim:
Aviao *av = new Aviao();
av->ini(1);
Aeroporto *aero = new Aeroporto();
aero->setAvi(av);
cout << aero->getAvi()->tipo << endl;
delete av;
delete aero;
Também podemos fazer a agregação assim:
int main() {
// Teste sem ponteiros
Aviao av; // Não precisa inicializar objetos com new nesse caso, em C++.
av.ini(1);
Aeroporto aero;
aero.setAvi(&av); // Não esqueça do & comercial
cout << aero.getAvi()->tipo << endl; // O tipo usa seta
return 0;
}