Posts Tagueados ‘c’
Como programar em C Orientado a Objetos
Olá, hoje eu vou dar um tempo na série “Coisas simples de se fazer em C++ que alguns ainda complicam” e irei falar sobre uma experiência minha tentando alguma maneira de programar em C orientado a objetos.
Sei que muitos vão pensar “pra quê isso?” ou dizer que é péssimo fazer isso ou coisa parecida, mas o intuito desse post é outro: é mostrar o que é possível fazer ou até mesmo enxergar alguma utilidade nisso. Nesse blog, procuro colocar coisas diferentes, curiosidades sobre programação e linguagens, porque acho que conteúdo “normal” já existem em muitos lugares na grande rede.
O que me instigou a fazer isso foi um post no CODARE “C: Escondendo o conteúdo de structs com tipos incompletos” de autoria do Thiago Santos, no qual ele cita sobre usar com orientação a objetos em C.
Li, achei interessante e quis, vamos dizer assim, dar um cara mais parecida de orientação a objetos ao que ele fez.
O primeiro passo foi pensar em como funcionam os famosos objetos.
Uma classe em uma linguagem orientada a objetos geralmente tem 2 tipos de elementos:
- Elementos de classe: elementos (funções e variáveis estáticas) que só são criados uma vez, todos os objetos da classe tem acesso ao mesmo elemento.
- Elementos de instância (ou objeto): elementos (atributos) que são criadas para cada objeto instanciado.
Ou seja:
class Animal
{
int age;
std::string specie;
static int count;
public:
int birthday();
};
No exemplo acima, age e specie são elementos de instância, ou seja, cada objeto têm o seus próprios. Já count e birthday() são de classe, pois todos os objetos dessa classe utilizarão o mesmo. O que ocorre no caso de funções é que na chamada da função, um ponteiro do objeto chamador é passado para a função. Isso faz com que não precise a cada instância de objeto criar uma nova função já que elas fazem a mesma coisa.
Algo como:
Animal animal, animal2; //lembrando que é APENAS uma ilustração do que acontece //não é assim que é realmente implementado mas é a mesma idéia //uma função só para todos os objetos de uma classe animal.birthday(); //vtable::animal::birthday(&animal); animal2.birthday(); //vtable::animal::birthday(&animal2);
A função birthday() é a mesma para as duas chamadas, o que muda é o ponteiro para os dados de cada objeto.
A minha implementação seguiu a idéia do Thiago Santos: uma classe person que tem os atributos name e age funções para instanciar, imprimir o nome e idade e deletar o objeto.
Vamos então dar uma olhada no nosso headerperson.h:
#ifndef PERSON_H__
#define PERSON_H__
//Incomplete type declaration
typedef struct person_private person_private;
typedef struct person {
//"private" data.
person_private* data;
//"class" functions
void (*free)();
void (*print)();
} person;
//instatiate a new person
person* new_person(const char*, int);
//pointer to the actual person in the context
person* __actual_person;
//sets the actual person
person* _(person* obj);
#endif
Nosso header contém a declaração incompleta de person_private leia aqui para saber o porquê, a definição da nossa “classe” person, as declarações das funções new_person() e _() e um ponteiro __actual_person.
Nossa “classe” person contém um ponteiro data para os dados que não poderão ser acessíveis através do objeto (name, age) além de ponteiros para funções (que serão nossos “métodos”).
A função new_person simplesmente instancia um objeto do tipo person.
O ponteiro __actual_person irá funcionar como o ponteiro passado para as funções de classe. Através do ponteiro saberemos qual objeto chamou a função.
A função _() seta o ponteiro __actual_person para que as funções sejam corretamente chamadas. Nota: não é thread safe. (hehehe)
Vamos ao nosso person.c:
#include "person.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//private data... visible only by the functions below
struct person_private
{
char* name;
int age;
};
//a "manual destructor"
void free_person()
{
free(__actual_person->data->name);
free(__actual_person->data);
free(__actual_person);
puts("Person sucessfuly freed!\nBye");
}
//prints
void print_person()
{
printf("%s -: %d\n", __actual_person->data->name,
__actual_person->data->age);
}
person* new_person(const char* name, int age)
{
//Allocate the object
person* new = (person*)malloc(sizeof(person));
new->data = (person_private*)malloc(sizeof(person_private));
//Initialize the data
new->data->name = (char*)malloc(strlen(name) * sizeof(char) + 1);
strcpy(new->data->name, name);
new->data->age = age;
//Set the functions pointers
new->print = print_person;
new->free = free_person;
return new;
}
//must call the objects with this function
person* _(person* obj)
{
__actual_person = obj;
return obj;
}
O que temos aí é a função _() que seta o objeto atual (__actual_person) para que possa ser utilizado a função com o objeto certo, a função new_person que funciona como nosso construtor, as outras duas funções que são os “métodos da classe” print e free e a definição da estrutura person_private que contém os atributos da classe.
Os comentários ajudam no resto
.
Vamos então ver o main.c que é o nosso teste:
#include <stdio.h>
#include "person.h"
int main()
{
//Instantiates 2 persons
person* person1 = new_person("Murilo", 21);
person* person2 = new_person("Rovane", 47);
//print
_(person1)->print();
_(person2)->print();
//free
_(person1)->free();
_(person2)->free();
}
Eis o resultado:
murilo@blacksheep:~/programacao/cobject$ gcc main.c person.c
murilo@blacksheep:~/programacao/cobject$ ./a.out
Murilo -: 21
Rovane -: 47
Person sucessfuly freed!
Bye
Person sucessfuly freed!
Bye
Nota: deve-se usar sempre a função _() para utilizar o objeto.
Fiquei pensando se tem como fazer uma espécie de gerador de classes nesse formato no próprio C (com macros por exemplo). Vou procurar saber se existe algo a respeito, são 04h40min da mardugada não estou mais com boas idéias.
Qualquer sugestão, bug, idéia, reclamação, estamos aí!
O que são enums e como utilizá-los melhor em C++

O que são os enums (C e C++)
Um enum (enumeração) é um tipo definido pelo usuário (programador) que consiste em constantes do tipo int nomeadas.
Um jeito tradicional de se declarar constantes em C e C++ é o seguinte:
#define BRASIL 0 #define ITALIA 1 #define PORTUGAL 2 #define ALEMANHA 3
E eis a maneira de fazer o mesmo utilizando enums:
enum
{
BRASIL,
ITALIA,
PORTUGAL,
ALEMANHA
};
Pode-se, alternativamente, criar um tipo para seu enum:
enum Paises
{
BRASIL,
ITALIA,
PORTUGAL,
ALEMANHA
};
E declarar uma variável desse tipo com:
Paises pais; //C++ apenas enum Paises pais; //C e C++
Num enum igual a esses acima, a primeira constante recebe o valor 0 e as subsequentes recebem o valor da constante anterior mais 1. Ou seja, BRASIL é 0, ITALIA é 1, PORTUGAL é 2 e ALEMANHA é 3.
Podemos também atribuir valores manualmente às constantes como em:
enum Paises
{
BRASIL = 2,
ITALIA, //ITALIA é igual a 3 (2 + 1)
PORTUGAL = 1,
ALEMANHA //ALEMANHA é igual a 2 (1 + 1)
};
Como podemos perceber no exemplo anterior, a mesma regra se aplica para os enums com valores manuais, o que não tiver um valor explicitamente inserido receberá o valor do anterior somado em 1. Percebemos também que podem haver constantes com o mesmo valor (BRASIL == ALEMANHA == 2).
Conversão
A conversão de uma constante de um enum para um inteiro por exemplo é feita automaticamente. Já o contrário não deve ser permitido pelo compilador.
enum Paises
{
BRASIL,
ARGENTINA,
VENEZUELA
};
...
int inteiro = VENEZUELA + 2; //4
Paises pais = 3; //ERRO
Uma melhor maneira de usar enums em C++
Veja o exemplo:
enum Paises
{
BRASIL,
ITALIA,
ALEMANHA
};
enum Uvas
{
RUBI,
ITALIA,
UMOUTROTIPODEUVA
};
Isso irá ocasionar um erro porque ITALIA já foi definido. A saida do meu compilador (g++ 4.3.2) foi a seguinte:
murilo@blacksheep:~/$ g++ enums.cpp
enums.cpp:14: error: conflicting declaration ‘ITALIA’
enums.cpp:8: error: ‘ITALIA’ has a previous declaration as ‘Paises ITALIA’
Mas e agora?? Eu quero ter dois enums diferentes que representam coisas diferentes mas que podem ter a mesma constante. Como?
A resposta é namespaces!
Em C++ podemos declarar nossos enums dentro de namespaces e assim termos as constantes em espaços de nomes diferentes. Nada de conflito agora hein g++!!!
namespace Paises
{
enum
{
BRASIL,
ITALIA,
ALEMANHA
};
}
namespace Uvas
{
enum
{
RUBI,
ITALIA,
UMOUTROTIPODEUVA
};
}
//*...*//
//Modo de uso:
std::cout << Uvas::ITALIA;
std::cout << Paises::ITALIA;
É isso aí galera, até a próxima.
Linguagens de programação – C++ – Direito de defesa
Um dia desses passeando por blogs ví um post que me chamou a atenção. O título é Linguagens de programação – C++ e, claro, chamou minha atenção, não apenas por causa do post assim com também por causa dos comentários sobre o post.
O objetivo desse post não é gerar um flame, até porque não atacarei nenhuma linguagem, só dissertarei sobre fatos.
Como converter um número para uma std::string e vice-versa
Que a biblioteca <iostream> oferece inúmeras facilidades para manipular I/O nós já sabemos mas, como converter um valor para uma std::string?
A bliblioteca <iostream> nos permite converter facilmente qualquer coisa para uma std::string usando a seguinte sintaxe (o exemplo a seguir converte um double, mas você pode substituir por qualquer coisa imprimível usando o operador <<): Leia o resto deste post »
Vector? Deque? Stack? Map? List? Como escolher o container STL correto?

- C++ STL Containers
4 eBooks que estou lendo
Ebooks que estou lendo e recomendo à quem gosta de programar.
Análise de quebra de proteção de software – monografia de dois alunos da universidade que estudo sobre quebra de proteção de software, engenharia reversa, arquitetura IA-32 e assembly compatível com o montador NASM.
Programação Orientada a Objeto em C++ UML – STL – GNU/Linux – Completíssimo. Desde o basicão mesmo até o mais avançado em C++, com boa didática e muitos exemplos. Aborda também AOO com UML e programação para GNU/Linux.
PC Assembly Language (inglês) – Muito bom mesmo. Em inglês “fácil”, o autor também explica desde o mais básico (como sistemas numéricos). Se você tem interesse em começar a estudar assembly, esse é um ótimo ponto de partida.
Art of Programming Contest SE (inglês) – Esse livro foi feito para os que gostam de contests de programação. Basicamente explica algoritmos, ensina técnicas de programação, programação em C e algumas outras coisas. Vale a pena conferir.
Fazendo contas de adição utilizando apenas operadores lógicos
Um dia desses na comunidade C/C++ Brasil orkut, ví um tópico com o título de “Operadores lógicos” e eu, como estou em pleno semestre de Sistemas Digitais e Linguagens de Montagem, fiquei curioso para saber o que era.
No tópico o cara dizia que precisava fazer uma adição de dois números mas teria que ser apenas com operadores lógicos.
Leia o resto deste post »