Dúvida gerais em C++

Oi.

Tenho uma pequena aplicação em PHP. Inicialmente pensei em rodá-la na Web, mas daí mudei de ideia e resolvi que seria desktop. Como seria ruim para os usuários ter que baixar um runtime, achei melhor converter as classes e testes para C++. Estou usando a IDE Code::Blocks e querendo usar wxWidgets.

Andei lendo um pouco sobre C++, mas não entendi muito. A começar pela separação de uma classe em interface (h) e implementação (cpp). Olha a classe que a IDE gerou:
Char.h

[code]#ifndef CHAR_H
#define CHAR_H

class Char {
public:
Char();
virtual ~Char();
protected:
private:
};

#endif // CHAR_H[/code]
Char.cpp

[code]#include “…/include/Char.h”

Char::Char() {
//ctor
}

Char::~Char() {
//dtor
}[/code]

Dúvida:
1- O código dentro de Char.cpp pertencerá obrigatoriamente à classe descrita no .h?
2- Essa estrutura é adequada? Qual a vantagem de separar a classe em 2 arquivos?
3- Tentei incluir um método com o uso de “this” e não consigo. Por quê? (abaixo)
Char.h

public: void setLevel(int); int getLevel(); Char(); virtual ~Char();
Char.cpp

int level; void setLevel(int level) { this.level = level; }

Tanto faz setLevel ou Char::setLevel.

Olá,
já faz tempo que não mecho com C++ mas acho que consigo responder… :smiley:

  1. Sim, pois o .h é o mapeamento de tudo que deve ser acessível no cpp
  2. É adequada e necessária, pois é através do .h que o .cpp pode ser usado como biblioteca para outros códigos
  3. A sintaxe está incorreta… no c++ usa-se o operador ->:

segue um exemplo de uso do this http://gracianotorrao.wordpress.com/2009/01/01/o-apontador-this-c/

Att.

Então this é um ponteiro.
Funcionou dessa forma:

void Char::setLevel(int level) { this->level = level; }
Mas precisei declarar o level como private no Char.h.

Meio estranho para mim ter que reclarar membros privados lá. Então o .h não é só a interface da classe.
Também é bem esquisito ter que usar o operador de escopo o tempo inteiro para implementar a classe.

Obrigado.

No caso do C++ há duas formas de implementar os métodos (ou funções): dentro ou fora da classe. Daí o operador :: é utilizado para indicar de qual classe o método pertence. Já a primeira forma é geralmente utilizada para pequenos códigos.

Att.

Não necessariamente. Não há nenhuma obrigação quanto à isso no cpp, embora seja uma boa prática. O cpp apenas exige que a definição (feita no .h) venha antes da implementação. Você pode inclusive declarar os dois no mesmo arquivo, ou fazer a implementação de um .h em dois arquivos .cpp, embora isso não seja uma boa prática.

Você separa a definição da implementação. Isso evita que seu código seja recompilado quando somente a implementação, e não a interface da classe, muda. Dá uma lida nesse artigo:
http://www.pontov.com.br/site/index.php/cpp/46-conceitos-basicos/95-compilacao-de-programas-cc

E, principalmente, nesse aqui:
http://www.caloni.com.br/blog/archives/declaracao-x-definicao

O C++ deixa as partes privadas junto da interface da classe, pois ele precisa saber o tamanho físico da classe, para que possa alocar memória corretamente. E para conhecer exatamente esse tamanho, é necessário conhecer o que há de privado. Infelizmente, isso quebra um pouco o encapsulamento, já que um programador de posse do .h, sabe o que a classe tem de privado.

É necessário entender um pouco melhor como o C++ gerencia isso.

Outra coisa. O arquivo que implementa o .h não precisa ser um código fonte. Pode ser uma library estática, já compilada.

Tome cuidado que o c++ é muito diferente do Java. Não tente programar em um como você faz no outro. Isso vai levar a um código ruim. Procure pegar um bom livro de cpp (como o do Deitel) e ver as diferenças. E, claro, depois disso, pegar um effective c++ da vida não faz mal a ninguém. :wink:

Beleza, deu pra entender um pouco melhor.

[quote=ViniGodoy]
Procure pegar um bom livro de cpp (como o do Deitel) e ver as diferenças.[/quote]
Não tem uma sugestão melhor, não? Eu tinha esse livro, mas passei adiante pra alguém aqui do GUJ porque é insuportável.
5 páginas pra explicar o que é um for pode ser aceitável pra um iniciante, mas pra quem já programa em alguma coisa, não dá :mrgreen:

Pelo menos por agora não vou fazer nada avançado. O programa é praticamente manipulação de um arquivo binário. É um editor de um jogo.
Vou precisar ver como fazer a interface gráfica com o wxWidgets de forma portável.

[quote=Schuenemann]Não tem uma sugestão melhor, não? Eu tinha esse livro, mas passei adiante pra alguém aqui do GUJ porque é insuportável.
5 páginas pra explicar o que é um for pode ser aceitável pra um iniciante, mas pra quem já programa em alguma coisa, não dá :mrgreen:[/quote]

Mas era o de C++ que você tinha? Pq o de C++ do Deitel é 100x melhor que o de Java.

De qualquer forma, você pode baixar o livro indicado no meu roadmap:
http://www.pontov.com.br/site/index.php/cpp/46-conceitos-basicos/88-roadmap-c

Ele é bem mais direto.

[quote=Schuenemann]Pelo menos por agora não vou fazer nada avançado. O programa é praticamente manipulação de um arquivo binário. É um editor de um jogo.
Vou precisar ver como fazer a interface gráfica com o wxWidgets de forma portável.[/quote]

Boa sorte. Qualquer dúvida é só perguntar por aqui. :slight_smile:

Ele mesmo. Acho os Deitel muito chatos.
Só recomendo pra quem é completamente iniciante, não só na linguagem, como também em programação. Qualquer um que programe sabe o que é uma variável, uma estrutura de repetição etc. Só falta saber a sintaxe e as particularidades daquela linguagem.

Vou ver sua sugestão.

Se você sabe programar, pegue um livro mais de referência sobre a sintaxe.
Pode ser o do André Bueno, indicado ali no site, ou mesmo uma apostila.

E, assim que dominar a sintaxe básica, parta para um Effective da vida.

Surgiu outra dúvida:

Estou pesquisando há algum tempo, mas não achei um jeito de encontrar o tamanho (quantidade de posições) de um array (no caso, de char).
Ele tem 5 posições. sizeof retorna 8. Achei lugares dizendo para dividir esse valor por (* (array)) ou (array[0]), mas retorna 8 de qualquer jeito (o tamanho do char deve ser 1).

Já outro lugar diz que não tem como encontrar o tamanho de um array em tempo de execução. Alguma dica?

Olá,
segue um exemple de como encontrar o tamanho de um vetor de um tipo qualquer:

[code]T vetor[];

size_t tamanho = (sizeof vetor)/(sizeof vetor[0]);[/code]
O valor de tamanho deverá ser igual ao de . Estou sem um compilador para testar mas acho que é isso.

Att.

Pois é, não dá certo:

char * mem = new char[5]; size_t s = (sizeof mem) / (sizeof mem[0]); cout << s << endl << endl << flush;

Imprime 8. Eu quero o número de posições (5).

Neste caso, quando o array é alocado dinamicamente, não sei se é possível saber o tamanho dele usando sizeof.

Att.

Putz… qual seria o motivo dessa limitação? Não é só armazenar o número de posições num atributo do array?

E quais são minhas alternativas? Guardar o tamanho numa variável, usar outro tipo, … ?

[quote=Schuenemann]Putz… qual seria o motivo dessa limitação? Não é só armazenar o número de posições num atributo do array?

E quais são minhas alternativas? Guardar o tamanho numa variável, usar outro tipo, … ?[/quote]

O que o operador sizeof retorna o número de bytes ocupados pelo operando, que pode ser uma variável ou um tipo genérico de dado. O problema é como fazer com que o operador ache a região de memória correspondente ao ponteiro. Faz já um tempo que não uso C/C++, mas não me lembro disso ser possível.

Sobre a segunda pergunta, não é possível. Vetores/arrays em C/C++ são somente ponteiros para regiões de memória. Não existem atributos atrelados a estes igual existem em Java. O que pode ser feito é armazenar o tamanho em uma variável de tipo inteiro (tipos int ou long).

A variável inteira seria passada como argumento para as funções que recebem o vetor, da mesma forma que é feita na função main:

#include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { printf("%d parametros:\n", argc); int i; for(i=0; i < argc; i++) { printf("%s %d\n", argv[i], strlen(argv[i])); } return 0; }
Nela o argc indica quantos argumentos foram passados no vetor de ponteiros argv (no qual cada posição aponta para um vetor de char). Não sei se há uma forma melhor, mas vendo pela própria função main do C/C++ tenho minhas dúvidas…

No código acima, a função strlen é utilizada para saber o tamanho das strings de cada uma das posições do vetor. Esta conta a quantidade de caracteres desde a primeira posição até o null (’\0’), que indica o final das strings no C/C++.

Att.

Em C++, existe o tipo vector, dentro da biblioteca padrão, a STL. Ele é como um ArrayList do Java. Além de crescer dinamicamente, possui um atributo para saber seu tamanho. Por ser feito baseado em template metaprogramming, sua performance é comparável a um array primitivo.

Se você está usando C++, recomendo fortemente que use vectors no lugar de arrays primitivos.

Além disso, a STL também tem a classe string. Ela é parecida com a string do java, com a diferença de por padrão ser mutável. Isso não é um grande problema em C++, pois objetos podem ser facilmente convertidos em imutáveis através da palavra const. Também recomendo fortemente o uso da classe String no lugar dos char*.

Como a classe string guarda o tamanho da string de uma forma eficiente, a performance geral dela costuma a ser superior a dos char*. Isso porque a função strlen tem a péssima performance de O(n) enquanto o método size() tem performance de O(1).

A classe string também suporta acesso a um caracter individual pelos [] e concatenação através do sinal de +. Pode ser declarada como const e não tem tanta apurrinhação quanto você tem com o char* na hora de criar vetores de strings.

[code]#include
#include
#include

using namespace std;

int main(int argc, char* argv[])
{
vector teste;
teste.push_back(“ViniGodoy”);
teste.push_back(“Schuenemann”);
teste.push_back(“Adelar”);
for (unsigned i = 0; i < teste.size(); i++)
{
cout << “O nome " << teste[i] << " tem " << teste[i].size() << " caracteres.” << endl;
}
}[/code]

Existe uma série de algoritmos prontos para se lidar com vector. A boost também tem meios utilitários como o BOOST_FOREACH, que faz um for each parecido com o do java.

Uma dica é. Se você vai usar C++, conheça a biblioteca padrão e a boost. Programar sem isso hoje em dia, é como usar somente a linguagem Java, sem usar nada que a API dele tem. Também é uma boa prática não programar em C++ como se fosse em C. São linguagens diferentes, então, procure usar as boas práticas da linguagem que você está usando.

O link da boost é: http://www.boost.org/

A STL não precisa ser baixada. Ela vem com qualquer compilador C++.

O mesmo programa acima usando um dos algoritmos prontos da STL para eliminar o for:

[code]#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

using namespace std;

void imprimeNome(const string& nome)
{
cout << "O nome " << nome << " tem " << nome.size() << " caracteres." << endl;
}

int main(int argc, char* argv[])
{
vector<string> teste;
teste.push_back(“ViniGodoy”);
teste.push_back(“Schuenemann”);
teste.push_back(“Adelar”);

std::for_each(teste.begin(), teste.end(), imprimeNome);
}[/code]

Uma coisa que adoro na Boost é que não perco o investimento mental que fiz com o Java.

Vejam o exemplo do ViniGodoy, mas usando também o Boost:

#include <vector>  
#include <string>  
#include <iostream>  
#include <boost/foreach.hpp>

using namespace std;  
using namespace boost;
   
 int main(int argc, char* argv[])   
{  
   vector<string> teste;  
   teste.push_back("ViniGodoy");  
   teste.push_back("Schuenemann");  
   teste.push_back("Adelar");  
  
   BOOST_FOREACH (const string& nome, teste) 
   {
      cout << "O nome " << nome << " tem " << nome.size() << " caracteres." << endl;  
   }
}  

O equivalente do BOOST_FOREACH no C++0X é o for ( : ) que infelizmente não foi implementado ainda em várias versões dos compiladores C++, como o Microsoft Visual Studio 2010 - nem sei se foi já implementado no g++.
O for ( : ) funciona igualzinho ao do Java.

[quote=ViniGodoy]
Isso porque a função strlen tem a péssima performance de O(n) enquanto o método size() tem performance de O(1). [/quote]
Pensei logo nisso quando vi a explicação. E ainda percorre inteira, toda vez que quiser saber o tamanho :?

Vou dar uma olhada no resto. Eu até ia usar a Boost.Test, mas troquei por UnitTest++.

[quote=Schuenemann][quote=ViniGodoy]
Isso porque a função strlen tem a péssima performance de O(n) enquanto o método size() tem performance de O(1). [/quote]
Pensei logo nisso quando vi a explicação. E ainda percorre inteira, toda vez que quiser saber o tamanho :?
[/quote]
Caso utilize a função strlen o recomendado é armazenar o valor em uma variável auxiliar. Como o Vini citou sempre que possível utilize a STL. Na maioria dos casos a performance é boa.

Att.