Organizacao de um aplicativo em C++ / + duvidas de iniciante

Estou aprendendo c++ e queria saber como é organizado um aplicativo em C++.
ps -> não estou usando IDE, pretendo fazer esse exemplo de baixo na unha mesmo, pq assim acho que aprendo mais…

Exemplo, vou criar o exemplo clássico de uma agenda de contatos em c++.

Até onde eu entendi… os headers (.h) funcionam como uma interface (similares ao java) com a diferenca de que nos headers pode haver implementações e nao somente a assinatura do metodo (classes abstratas do java???).

Em Java nem sempre precisamos de interfaces para fazer alguma coisa, no c++ é uma boa prática ou é igual ao java, não é necessário tbm? as classes devem ser DECLARADAS em um header ou em um arquivo de implementação? (.cpp) uma arquivo por classe?

agora umas duvidas bobas de iniciante:

  • a declaracao using namespace std; é semelhante ao static import do java?

  • existe garbage collector ou algo parecido no c++?
    pq a duvida?

Quando eu crio um objeto no c++ e depois de utiliza-lo o destrutor é chamado e toda a memoria utilizada para manter informações sobre aquele objeto é liberada? Se sim, caso esse objeto tenha um atributo que é um ponteiro pra um array por exemplo, criado utilizando malloc. Quando objeto morre, aquela área reservada utilizando o malloc morre tbm, ou isso deve ser feito pelo programador??

enfim, pessoa que os moderadores tenham pena de mim, sei que o forum é sobre java, mas é tao escasso bom material aqui sobre a linguagem que tive que vir pra cá, sei que aqui tem bons programadores de c++.

thx a todos… de acordo com o tempo que vou estudando e for sugindo duvidas eu posto aqui :smiley:

EDIT:

  • A implementação dos métodos da classe devem ser feitos dentro da classe ou fora? existe uma grande diferença entre as duas formas?

Não, não é isso. O C++ tem dois conceitos distintos, o de declaração e o de definição.

Declarar uma classe significa dizer ao compilador qual será a assinatura de seus métodos, e quais propriedades ela irá conter. A declaração vai no .h.
A definição é a implementação do método em si. Ela estará no arquivo .cpp, ou pode estar já compilada em alguma das libs que você incluiu no seu projeto.

Não confunda o .h com interfaces do Java, pois, embora ali não estejam escritas as definições dos métodos, elas estarão escritas em algum lugar, geralmente no arquivo .cpp correspondente.

Leia também:
http://pontov.com.br/site/cpp/46-conceitos-basicos/95-compilacao-de-programas-cc
http://pontov.com.br/site/cpp/46-conceitos-basicos/155-como-usar-bibliotecas-cc

No C++ usam-se 2 arquivos por classe. Um para a definição (.h) e outro para as declarações (.cpp).
A definição é também chamada de interface pública da classe, mas esse conceito não deve ser confundido com o de “interface” do Java. Mesmo as classes em Java tem uma interface pública, que é a que o “code completion” apresenta para você.

Uma classe não precisa necessariamente ter uma interface. Na verdade, embora seja possível criar interfaces em C++, não existe uma palavra chave para isso.

Não, é similar ao import, sem o static.
Detalhe, o #include não é similar ao import.

Não existe.
Objetos criados no stack (sem o uso de new) são automaticamente destruídos quando saem de escopo, e são automaticamente copiados ao serem passados por parâmetro.
Objetos criados no heap (com new) devem ser explicitamente deletados com delete.

Para mais informações, leia:
http://pontov.com.br/site/cpp/43-smart-pointers/52-smart-pointer-introducao
http://pontov.com.br/site/cpp/46-conceitos-basicos/335-exception-safety-e-gerencia-de-recursos

std::string, toda vida.

Sim, basta fazer:

Acredito que QT e, infelizmente, a MFC.

http://www.pontov.com.br/files/cpp/roadmapcpp/ApostilaProgramacaoCppv045.pdf

Sem problemas, até por isso temos um fórum de outras linguagens.

por exemplo:

quando eu uso “using namespace std” não é necessario eu utilizar "#include "
???

Onde fica a implementacao de tudo isso?? dentro do compilador??
pois nao lembro de baixar um sdk nem nada

estou utilizando ubuntu + g++

EDIT:

quando eu dou um #include <algo.h> eu estou apenas importando sua ‘interface’, mas como você disse todo header tem sua implementacao, nao é possivel criar um header para ser implementado depois??

Não é possível criar um header para ser implementado depois.
O C++, assim como o Java, tem uma biblioteca padrão, chamada de STL (Standard Template Library). Ela tem um conjunto padrão de funções e classes, como as classes std::string e std::vector.

Você precisa fazer o #include <string> se quiser usar a classe String. O que esse comando faz é dizer ao seu programa para “recortar e colar” o .h da classe string no seu arquivo, no ponto onde o #include é dado.

O string está no pacote (no C++ chamado de namespace) std. std é a sigla de standard. Portanto, quando você faz using namespace std; você pode parar de usar o std:: na frente do nome da classe e escrever somente string.
Em java é muito similar. Você pode escrever o nome de uma classe de maneira completa como java.util.ArrayList ou de maneira resumida, desde que faça o import, usando somente ArrayList.

A diferença é que em java você não precisa indicar em que arquivo o import foi declarado, pois o compilador se vira para encontrar isso sozinho.

duvida:

http://pt.wikibooks.org/wiki/Programar_em_C%2B%2B/Manipulando_strings#comparar_frases nesta parte que ele fala sobre a comparacao

ele diz que essa comparacao da como verdadeiro… mas não dá… ou eu que não entendi o que ele quis dizer ali?

[code]#include
#include
#include <string.h>

using namespace std;

int main(void){

char oi[10] = "chess";
char o2[15] = "check";

if(strcmp(oi, o2) == 0){
	cout << "Sao Iguais C";
} else {
	cout << "Sao Diferentes C";
}

return 0;

}[/code]

[quote=faeldix]duvida:

http://pt.wikibooks.org/wiki/Programar_em_C%2B%2B/Manipulando_strings#comparar_frases nesta parte que ele fala sobre a comparacao

ele diz que essa comparacao da como verdadeiro… mas não dá… ou eu que não entendi o que ele quis dizer ali?

[code]#include
#include
#include <string.h>

using namespace std;

int main(void){

char oi[10] = "chess";
char o2[15] = "check";

if(strcmp(oi, o2) == 0){
	cout << "Sao Iguais C";
} else {
	cout << "Sao Diferentes C";
}

return 0;

}[/code][/quote]

Não é igual mesmo. Não será uma errata? E outra, porque não usar string?

[code]#include
#include
#include <string.h>

using namespace std;

int main(void){

string oi  = "chess";
string o2 = "check";

if(strcmp(oi, o2) == 0){
	cout << "Sao Iguais C";
} else {
	cout << "Sao Diferentes C";
}

return 0;

}[/code]

No texto ele diz que o valor será “positivo”, e não igual a zero. Ou seja, não significa que as duas strings serão iguais.
Positivo é qualquer valor maior do que zero.

Isso significa que a palavra check deve vir antes de chess.

É que na verdade, o strcmp funciona exatamente igual ao método compareTo da classe String. E a tabela de onde você tirou o chess e o check mostra isso.

O ideal mesmo é usar a classe std::string. Ficar manipulando char* é coisa de programador C.

There are several essential differences.

  1. In C++, there are public and private sections, started by the keywords public and private. In Java, each individual item must be tagged with public or private.
  2. The class definition only contains the declarations of the methods. The actual implementations are listed separately.
    3. Accessor methods are tagged with the keyword const
  3. There is a semicolon at the end of the class

é necessário isso mesmo??? Qual a serventia??

O C++ implementa um conceito chamado de “constness”. Quando você declara um objeto como const, não está dizendo que apenas a referência dele é const, mas sim, o objeto mesmo.

Portanto, se você fizer:

Ele não vai deixar você chamar nenhum método de abc que altere a string.

Mas, como a linguagem sabe quais métodos alteram ou não a String? Por que os métodos que não alteram o estado da classe são marcados como const.

Essa última afirmação não está 100% correta. Um getter que altere o estado da classe, embora seja exceção, não deve ser marcado como const. Na verdade, ao dizer que um método é const, o C++ irá te proibir de alterar o valor de qualquer atributo.

É assim que se declara um método const:

class Exemplo { private: int x; public: int getX() const; };

Vini obrigado pela força cara…

Mas vamos la… mais duvidas:

Li isso na apostila que encontrei no seu site:

so nao encontrei o pq…

Por que o using irá valer para todos os arquivos que importarem aquele .h.

É importante lembrar que o #include não é igual ao import do Java (o using é que é).

#include equivale a dizer para o pré-processador pegar o conteúdo de um arquivo e colocar no ponto onde o #include foi dado. Um exemplo de uso diferente do #include é no jogo Quake. Eles colocaram um 3D Studio da vida para calcular os vetores normais dos modelos, criando 256 normais que mapeavam uma esfera. Então salvaram um arquivo nesse formato, com 256 chanves como essa:

Então, no C++ fizeram isso aqui:

double [][] anorms = { #include "anorms.txt" };

O pré-processamento ocorre antes da compilação.

Portanto um using num arquivo .h irá ser dado sobre qualquer arquivo que o incluir. O programador acaba ganhando de graça um using, o que vai tirar o sentido de usar namespaces.

perfeito vinicius… obrigado…

tentei implementar um singleton

header

class Teste { Teste(){} Teste(Teste&){} public: static Teste getInstance(); void imprime(); };

cpp

[code]#include
#include “teste.h”

using namespace std;

Teste Teste::getInstance(){
static Teste t;
return t;
}

void Teste::imprime(){
cout << “Olá” << endl;
}[/code]

main

[code]#include
#include “teste.h”

using namespace std;

int main(){
Teste::getInstance().imprime();
return 0;
}[/code]

TA OK?

Tentei colocar a variavel estatica na classe… mas nao conseguia “puxar” com o ‘->’ pra chamar a funcao imprime ;/

tipo assim:

header

class Teste { static Teste *p; Teste(){} Teste(Teste&){} public: static Teste* getInstance(); void imprime(); };

cpp

[code]#include
#include “teste.h”

using namespace std;

Teste* Teste::getInstance(){
p = new Teste;
return p;
}

void Teste::imprime(){
cout << “Olá” << endl;
}[/code]

erro:

[quote]rafael@rafael-note:~/Área de Trabalho/C/C++$ g++ teste.h teste.cpp operadores.cpp
/tmp/cclMyyDI.o: In function Teste::getInstance()': teste.cpp:(.text+0x1f): undefined reference toTeste::p’
teste.cpp:(.text+0x24): undefined reference to `Teste::p’
collect2: ld returned 1 exit status
[/quote]

Cuidado, você está retornando por valor. Isso tentará criar uma cópia de Teste.

Mude o retorno do getInstance() para Teste&. Assim você retorna só a referência, sem cópias.

Vai ficar assim:

[code]//Teste.h
class Teste {
Teste(){}

Teste(const Teste&);
Teste operator = (const Teste&);

public:
static Teste& getInstance();
void imprime();
};[/code]

[code]#include <iostream>
#include "teste.h"

using namespace std;

Teste& Teste::getInstance(){
static Teste t;
return t;
}

void Teste::imprime(){
cout << "Olá" << endl;
}[/code]

e utilizando a variavel dentro da classe e não do metodo??

Basicamente a mesma coisa, mas não vejo muito por que ser desse jeito:
Vai ficar assim:

[code]//Teste.h
class Teste {
private:
static Teste t;

Teste(){}
//Não é necessário fornecer implementação
//vazia para esses 2. 
Teste(const Teste&);
Teste operator = (const Teste&);

public:
static Teste& getInstance();
void imprime();
};[/code]

[code]#include <iostream>
#include "teste.h"

using namespace std;

Teste& Teste::getInstance(){
return t;
}

void Teste::imprime(){
cout << "Olá" << endl;
}[/code]

Vinny me ajude a entender o que ele quiser dizer nessa parte…

[quote]? Se uma função espera uma referência e recebe um ponteiro ela aceita mas pode causar um bug.
Exemplo:
//Prototipo do método:
//O método espera uma referência
TBitmap(const TDC& dc, const TDib& dib);
TDib* dib;
TBitmap (dc,dib); //Uso errado, passando um ponteiro
TBitmap (dc,*dib); //uso correto, passando o objeto
? 2 BUG: Digamos que você deseja passar um objeto como parâmetro para um método
f(nomeclasse obj). Como você esta passando o objeto por cópia, vai criar uma cópia do objeto.
Depois vai usar o objeto dentro do método, e, ao encerrar o método, o objeto é deletado. Se o objeto
original tinha algum ponteiro com alocação dinâmica, este ponteiro é deletado, sendo deletado o
bloco de memória por ele acessado. Assim, o ponteiro do objeto original aponta agora para um
monte de lixo. Para que isto não ocorra você deve passar uma referência do objeto, de forma que
é passado o objeto e não uma cópia deste, quando sair de escopo o objeto não é eliminado.
[/quto]

pq tentei causar esse bug… mas nao funcionou…


  • uma duvida

construtores sao definidos no .h ou no .cpp?
variaveis estaticas sao inicizalidas no .h ou no .cpp?

Esse bug está mal colocado, meio cedo para falar desse tipo de detalhe, e ainda de forma tão superficial.
Mas existe mesmo. Considere a seguinte classe:

[code]class Foo {
private:
MeuObjeto* obj;
public:

Foo() : obj(new MeuObjeto()) {
}

   ~Foo() {
       delete obj;
   }

};[/code]

Agora, considere que você passa Foo por cópia, como no método abaixo:

Veja o que acontece nesse código abaixo:

Foo foo; doSomething(foo); cout &lt;&lt; foo.getObj().getName(); //Crash
Essa classe não tem construtor de cópia implementado, portanto, ele vai fazer uma cópia do objeto ao entrar em doSomething, chamando a implementação padrão. Essa implementação faz a cópia do ponteiro, mas não do objeto que ele aponta (ela se comporta como o método clone() padrão do Object do Java).

Porém, a cópia de Foo será destruída ao final do método doSomething, pois a variável local criada no parâmetro será destruída, fazendo com que o código delete obj seja executado. Ao ser executado, isso irá destruir o objeto apontado por obj. Assim, fora do método, a variável foo agora está apontando para um objeto que não existe mais, fazendo o método getName() crashear.

Há três formas de resolver esse problema:

  1. Desabilitar o construtor de cópia e o operador de =. Para fazer isso, basta declara-los sem implementação na sessão private da sua classe - isso gerará um erro de compilação caso você tente fazer uma cópia acidental. Na verdade, é uma boa prática fazer isso sempre, só removendo do private se você efetivamente for se preocupar com cópia na classe.
  2. Implementar o construtor de cópia e o operador de = para que façam a cópia do que é apontado;
  3. Usar um smart pointer, como o std::shared_pointer, caso você queira compartilhar, ou um std:unique_ptr, caso não queira.

Eu elaborei uma aula sobre boas práticas de C++, que você pode baixar aqui:


Explica algumas pegadinhas como essa. Essa é uma das aulas que ministro na pós de jogos. Mas os slides não são lá tão úteis sem eu explica-los, hehehe.

A aula é baseada nos livros Effective C++ e More Effective C++, do Scott Meyers. Leitura obrigatória depois que você vencer a sintaxe básica.

Você faz a declaração no .h e a definição no .cpp.

Novamente, declara-se no .h e define-se no .cpp.

No .h você só colocará código se:

  • A função for inline;
  • Você usar templates.

Lembre-se também que código escrito no .h é público, pois não é compilado.

bkna vinny… meio do ano teremos um evento aqui na universidade e como tenho boa relação com a coordenação do curso, poderíamos ver a possibilidade de lhe trazer, seria uma honra.

Ainda por cima me ajudaria pois estou criando um jogo para Android que inclusive estarei apresentando no Computer on The Beach em floripa esse ano.