Confuso com C e C++, Misturando funções. [RESOLVIDO]

1. Confuso com C e C++, Misturando funções. [RESOLVIDO]

Nick Us
Nick-us

(usa Slackware)

Enviado em 24/05/2020 - 19:40h

Estudei C primeiramente. Então montei vários pequenos programas que não servem pra nada, mas foi com eles que criei exemplos para eu entender C. Ainda estou aprendendo C, não sei tudo, apenas o básico.

Então já com alguma noção de C, estou estudando C++, tentando compreender as diferenças, montando os mesmos programinhas que fiz em C, porém agora em C++, e claro notei muitas diferenças.

Neste momento, um programinha em C que informa a Data/Hora que eu fiz, ao tentar fazer ele em C++, vi que exemplos na Internet não usam exatamente C++, o que usa é a mesma coisa que tenho em C. Tipo, o mesmo comando, a mesma função, existem até quem diga que em C é melhor, pq C++ não tem um suporte bom para isso e etc...

Então foi ai que me veio uma Gigantesca dúvida! O que é melhor em meu Código? Uso C, ou C++?

O Caso é que estou fazendo um pequeno Banco de Dados de Contatos. Inicialmente por eu apenas saber C e nada de C++ coloquei ele funcionando com a maior parte do Código feito em C, deixando o C++ apenas para Janelas e Controles. O que significa que usei char (vetores) ao invés de string e etc...

Atualmente eu resolvi modificar todo o programa para código em C++ troquei os char (vetores) para string e etc... Ainda estou mudando a forma de Ler e Gravar o arquivo que ainda não dominei em C++. Mas fiquei pensando? Será que o código em C não é mais otimizado, mais rápido, mais eficiente? Talvez por usar menos bibliotecas?

Sei que usar uma String é mais fácil do que um vetor, mas o que estou perdendo ao usar algo mais complexo?

Embora claro, não posso ter o código inteiro em C, nem mesmo compilar ele em C, porque uso Classes da wxWidgets C++, ou seja, estou preso a compilar o programa em C++ com todos os lixos que uma biblioteca deles possa trazer, ainda assim, é melhor usar C para o que eu puder e deixar o C++ apenas qdo for necessário?

Sei que a pergunta parece complexa, mas ela é a BASE para tomar decisões de como eu vou criar meus programas. Eu gosto dos meus códigos pequenos, gastando poucos recursos, rápidos. Nunca gostei de códigos grandes! E claro não gosto de códigos escondidos por trás de uma função, pq nada adianta eu digitar uma linha apenas qdo essa linha é na verdade 100 mil linhas escondidas em alguma função complexa!


  


2. MELHOR RESPOSTA

Paulo
paulo1205

(usa Ubuntu)

Enviado em 27/05/2020 - 06:35h

Não sei qual material você está usando para estudar. Contudo, pela declaração, por exemplo, relacionada à função para exibir a hora, dizendo que “C++ não tem um suporte bom para isso”, provavelmente é porque o material que você está usando é antigo ou desconhece funcionalidades trazidas pelas bibliotecas do C++ em versões a partir de 2011 (tivemos atualizações do padrão em 2011, 2014, 2017 e a de 2020 deve estar para sair).

Reconheço que com um ciclo de atualizações a cada três anos, fica mesmo um pouco difícil para quem não é da área — e talvez até para quem é da área — manter-se rigorosamente atualizado.

(Obs.: no caso específico de std::put_time(), sobre a qual eu falei no outro tópico recente que você abriu, eu mesmo nunca a tinha usado, e não sei se posso dizer que alguma vez já tinha ouvido falar dela e esquecera, ou se nunca ao menos tinha ouvido falar. A gente tende a só conhecer o que usa mais frequentemente. Se não olhar para os lados de vez em quando, vai ficar sempre fazendo tudo do mesmo jeito.)

Talvez o que a biblioteca da linguagem oferece seja um pouco menos relevante do que algo que o framework que você utiliza possa trazer. Não sei o wxWidgets, que nunca usei, mas o Qt, que eu vou pegar como exemplo, tem uma hierarquia de classes próprias que substituem equivalentes nas bibliotecas padrões do C e do próprio C++. Se você estiver usando Qt, pode ser mais útil usar exclusivamente QString no seu programa, em lugar de std::string, ou QDateTime em lugar de time_t e std::tm e funções relacionadas, porque você vai acabar sendo forçado a usar o tipo do Qt na hora de usar a interface gráfica. Misturar tipos semelhantes no mesmo programa acaba criando um tipo de inchaço e perda de desempenho por causa da necessidade de converter de um tipo para outro tipo funcionalmente equivalente a cada vez que você transfere dados internos para a interface gráfica ou recebe dados da GUI para os seus objetos internos.

Há quem critique o fato de o Qt não usar mais tipos nativos ou da biblioteca padrão, mas eu compreendo a escolha de projeto feita pelos implementadores do Qt. O Qt é multiplataforma, e tem de funcionar do mesmo modo em todas as plataformas que suporta. No entanto, os compiladores e as bibliotecas que os acompanham têm muitas variações entre sino que tange a certos tipos fundamentais, como wchar_t, que no Windows é de 16 bits e no mundo UNIX e Linux tende a ser sempre de 32 bits. Existem várias outras diferenças como essa, mas essa, sozinha, já tenderia a causar dificuldades de portabilidade em todas as operações com strings. Uma forma supostamente simples de lidar com esse problema seria fazer conversões de tipo cada vez que algum dado interno tivesse de ser apresentado ou que algum valor recebido tivesse de ser armazenado internamente, só que nós já vimos que essas conversões degradam o desempenho, aumentam o tamanho do código e, no fim das contas, não agregam valor nenhum. Então o pessoal do Qt fez algo a princípio anti-intuitivo, que é meio que reinventar a roda (várias rodas, aliás), mas que, no final das contas, melhorava não apenas a portabilidade, mas o próprio desempenho e o tamanho de código por meio da eliminação de conversões, desde que você use exclusivamente (ou tão próximo de exclusivamente quanto possível) os tipos que o Qt lhe apresenta.

Voltando ao wxWidgets, pareceu-me, pelo que eu li, que ele usa muita coisa da biblioteca padrão do C++, incluindo std::string. Sendo esse o caso, você deve preferir usar os mesmos tipos que ele usa. Caso contrário, você pode acabar provocando operações de conversão de tipos que poderiam ser evitadas, o que aumenta o inchaço e degrada o desempenho, mesmo que seja uma mera conversão de array de caracteres para std::string.

Tirando isso, vale sempre o princípio de que não existe almoço grátis. A conveniência sintática do C++ cobra seu preço. Quase sempre esse preço é pago no momento da compilação, não no de execução, o que é ótimo, pois é um preço que o seu usuário não vai pagar.

Mas existe também um lado de que você, como programador, tem de cuidar: a sintaxe simples pode às vezes esconder uma operação que é custosa. Um exemplo que já foi comentado é a conversão de tipos que pode ocorrer em expressões simples, como ilustra o exemplo abaixo.

void f(const std::string &s){ /* faz alguma coisa com s */ }

int main(){
// Vai provocar um milhão de operações de construção por conversão de tipo, e depois um milhão
// de chamadas a f() com o valor convertido para o objeto temporário, e, por fim, um milhão de
// desconstruções do objeto temporário criado.
for(int i=0; i<1000000; ++i)
f("Paulo");

// Aqui não vai haver conversão de tipo nem desconstrução de objeto dentro do laço
// de repetição: f() vai ser invoca um milhão de vezes usando uma referência para o
// mesmo objeto, construído e desconstruído uma só vez.
const std::string paulo("Paulo");
for(int i=0; i<1000000; ++i)
f(paulo);
}


Quanto a usar C ou C++, acho que você já perguntou isso outras vezes. Vamos resumir do seguinte modo: se você já tem funções prontas em C, preferencialmente oferecidas em forma de biblioteca, use essas funções do jeito como estão. Se não as tiver prontas, se elas não estiverem em forma de biblioteca e se sua eventual reimplementação em C++ for simples, ou ainda se você perceber que seu uso vai incorrer em perda de desempenho por causa de múltiplas conversões de tipo ou cópia de valores de um lado para o outro, faça-a ou reimplemente-as em C++.

E note que “fazer em C++” não necessariamente significa que você vai ter de socar tudo dentro de classes (como faz o Java, mesmo para o que não precisaria estar dentro de uma classe). C++ é multiparadigma: se lhe bastarem funções, use funções; se lhe bastarem estruturas que não sejam classes, use estruturas; se tiver de usar classes de tipos concretos, sem polimorfismo, use desse modo; se precisar de polimorfismo, use-o com sabedoria; se lhe ajudar programação genérica, use-a. Seu programa não vai ser mais em C++ ou menos em C++ por causa do paradigma que você escolher (pode sê-lo por outros fatores, especialmente se você usar sintaxe ou construções do C que são expressamente repudiadas em C++, tais como conversão de tipo na forma “(nome_do_tipo)valor_a_ser_convertido” em vez de construtores de conversão de tipo ou de conversão explícita por meio de static_cast/const_cast/dynamic_cast/reinterpret_cast, ou malloc()/free() em lugar de new/delete ou new[]/delete[]).


... Então Jesus afirmou de novo: “(...) eu vim para que tenham vida, e a tenham plenamente.” (João 10:7-10)

3. Re: Confuso com C e C++, Misturando funções. [RESOLVIDO]

Nick Us
Nick-us

(usa Slackware)

Enviado em 28/05/2020 - 15:06h

paulo1205 escreveu:
Talvez o que a biblioteca da linguagem oferece seja um pouco menos relevante do que algo que o framework que você utiliza possa trazer. Não sei o weWidgets, que nunca usei, mas o Qt, que eu vou pegar como exemplo, tem uma hierarquia de classes próprias que substituem equivalentes nas bibliotecas padrões do C e do próprio C++. Se você estiver usando Qt, pode ser mais útil usar exclusivamente QString no seu programa, em lugar de std::string, ou QDateTime em lugar de time_t e std::tm e funções relacionadas, porque você vai acabar sendo forçado a usar o tipo do Qt na hora de usar a interface gráfica. Misturar tipos semelhantes no mesmo programa acaba criando um tipo de inchaço e perda de desempenho por causa da necessidade de converter de um tipo para outro tipo funcionalmente equivalente a cada vez que você transfere dados internos para a interface gráfica ou recebe dados da GUI para os seus objetos internos.

Importantíssimo essa informação para mim e para muitas outras pessoas! Pois eu não estava vendo por esse lado! E sempre me incomodou muitas vezes essas criações. Na wxWidgets também existe essas similiridades, que hoje levarei em conta para analise de desempenho, Eu via apenas o mais novo como algo mais pesado, me esqueçendo da transição e comunicação entre eles.


Há quem critique o fato de o Qt não usar mais tipos nativos ou da biblioteca padrão, mas eu compreendo a escolha de projeto feita pelos implementadores do Qt. O Qt é multiplataforma, e tem de funcionar do mesmo modo em todas as plataformas que suporta. No entanto, os compiladores e as bibliotecas que os acompanham têm muitas variações entre sino que tange a certos tipos fundamentais, como wchar_t, que no Windows é de 16 bits e no mundo UNIX e Linux tende a ser sempre de 32 bits. Existem várias outras diferenças como essa, mas essa, sozinha, já tenderia a causar dificuldades de portabilidade em todas as operações com strings. Uma forma supostamente simples de lidar com esse problema seria fazer conversões de tipo cada vez que algum dado interno tivesse de ser apresentado ou que algum valor recebido tivesse de ser armazenado internamente, só que nós já vimos que essas conversões degradam o desempenho, aumentam o tamanho do código e, no fim das contas, não agregam valor nenhum. Então o pessoal do Qt fez algo a princípio anti-intuitivo, que é meio que reinventar a roda (várias rodas, aliás), mas que, no final das contas, melhorava não apenas a portabilidade, mas o próprio desempenho e o tamanho de código por meio da eliminação de conversões, desde que você use exclusivamente (ou tão próximo de exclusivamente quanto possível) os tipos que o Qt lhe apresenta.

Também muito importante sua observação, noto que preciso também controlar o meu nível de crítica, porque acaba sendo comum eu criticar ou não gostar de alguma coisa e obviamente porque não entendi o motivo da existência dela, ou seu objetivo e funcionamento, preciso melhorar isso. Ainda bem que tudo o que me incomoda e que acho errado, costumo perguntar para ter opiniões diferentes das pessoas para que eu entenda se estou pensando correto ou se estou completamente equivocado.


Voltando ao wxWidgets, pareceu-me, pelo que eu li, que ele usa muita coisa da biblioteca padrão do C++, incluindo std::string. Sendo esse o caso, você deve preferir usar os mesmos tipos que ele usa. Caso contrário, você pode acabar provocando operações de conversão de tipos que poderiam ser evitadas, o que aumenta o inchaço e degrada o desempenho, mesmo que seja uma mera conversão de array de caracteres para std::string.

Sim esses seus esclarecimentos acima sobre isso, me ensinaram a ver de outra forma, ainda bem!


Tirando isso, vale sempre o princípio de que não existe almoço grátis. A conveniência sintática do C++ cobra seu preço. Quase sempre esse preço é pago no momento da compilação, não no de execução, o que é ótimo, pois é um preço que o seu usuário não vai pagar.

Boa observação e muito importante, como sou iniciante e ainda não tenho muita experiência em compilação, em como funciona e como são esses resultados, não passou por minha cabeça essa diferença, de verdade eu nunca me preocupei com o tempo de compilação, pq nem cheguei nesse nível ainda, visto que tudo que compilo leva segundos (Programas que eu criei claro, não considerando programas para o Linux de terceiros), minha preocupação sempre é com a execução e consumo de recursos, mesmo claro, não chegando a nada ainda que consuma! Mas sei que no futuro, meus programas podem e obviamente poderão consumir recursos importantes.


Mas existe também um lado de que você, como programador, tem de cuidar: a sintaxe simples pode às vezes esconder uma operação que é custosa. Um exemplo que já foi comentado é a conversão de tipos que pode ocorrer em expressões simples, como ilustra o exemplo abaixo.

void f(const std::string &s){ /* faz alguma coisa com s */ }

int main(){
// Vai provocar um milhão de operações de construção por conversão de tipo, e depois um milhão
// de chamadas a f() com o valor convertido para o objeto temporário, e, por fim, um milhão de
// desconstruções do objeto temporário criado.
for(int i=0; i<1000000; ++i)
f("Paulo");

// Aqui não vai haver conversão de tipo nem desconstrução de objeto dentro do laço
// de repetição: f() vai ser invoca um milhão de vezes usando uma referência para o
// mesmo objeto, construído e desconstruído uma só vez.
const std::string paulo("Paulo");
for(int i=0; i<1000000; ++i)
f(paulo);
}


Amei também essa explicação! O que mostra que preciso estudar ainda mais! pra entender ainda mais as pequenas coisas! Quanto mais aprendo, mais descubro que não sei nada! E esse exemplo ainda me assustou bastante, porque eu julgaria o 1º Exemplo o melhor a se fazer! E pelo visto vou ter que revisar todos os meus conceitos e me esforçar mais para saber diferenciar corretamente o que é Otimizado e o que não é! Aliás, terei que criar inúmeros testes até compreender bem esse conceito. Meu nível ainda é baixo, então eu pensava que escrever é gastar recursos, então eu pensava, se estou declando uma constante, estou gastando 1 recurso e com isso meu programa fica mais pesado. E por falta de conhecimento, não tinha e ainda acho que não tenho capacidade de avaliar o que de verdade gasta ou não recursos conforme o que vc mostrou! O que ao menos agora SEI que é um FATOR importante que terei que aprender! UAU!


Quanto a usar C ou C++, acho que você já perguntou isso outras vezes. Vamos resumir do seguinte modo: se você já tem funções prontas em C, preferencialmente oferecidas em forma de biblioteca, use essas funções do jeito como estão. Se não as tiver prontas, se elas não estiverem em forma de biblioteca e se sua eventual reimplementação em C++ for simples, ou ainda se você perceber que seu uso vai incorrer em perda de desempenho por causa de múltiplas conversões de tipo ou cópia de valores de um lado para o outro, faça-a ou reimplemente-as em C++.

Entendi, mas aqui vai cair no fator acima, tenho que saber reconhecer o que consome e o que não consome!


E note que “fazer em C++” não necessariamente significa que você vai ter de socar tudo dentro de classes (como faz o Java, mesmo para o que não precisaria estar dentro de uma classe). C++ é multiparadigma: se lhe bastarem funções, use funções; se lhe bastarem estruturas que não sejam classes, use estruturas; se tiver de usar classes de tipos concretos, sem polimorfismo, use desse modo; se precisar de polimorfismo, use-o com sabedoria; se lhe ajudar programação genérica, use-a. Seu programa não vai ser mais em C++ ou menos em C++ por causa do paradigma que você escolher (pode sê-lo por outros fatores, especialmente se você usar sintaxe ou construções do C que são expressamente repudiadas em C++, tais como conversão de tipo na forma “(nome_do_tipo)valor_a_ser_convertido” em vez de construtores de conversão de tipo ou de conversão explícita por meio de static_cast/const_cast/dynamic_cast/reinterpret_cast, ou malloc()/free() em lugar de new/delete ou new[]/delete[]).

Interessante, qdo eu compilo em C++ eu gosto de seguir as normas! Acho que depois que aprendi com vc, como compilar, como respeitar o compilador, como respeitar e interpretar seus Warnings. Gosto que esteja tudo bonitinho. A Parte boa de aprender a compilar e vencer os Warnings é que somente assim que podemos quebrar alguma regra! As vezes pego exemplos na Internet, e que para que eu os veja funcionando e analise se irei usar ou aproveitar, para alguns desses exemplos eu abro exceção na compilação para ve-los rapidamente em ação. E ao avaliar, se usarei aquele exemplo, então sim, ele terá que respeitar as regras dos Warnings, então me esforço para consertar o exemplo e colocar ele bonitinho no Padrão que o compilador exige! Não sei porque gostei de fazer assim! No Início eu ficava chateado mesmo com o compilador, mas depois quando aprendi a respeitar as regras dele, aprendi a buscar a solução para que o programa seja aprovado com nota 10.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts