collapse

* Posts Recentes

Emulador NES em ESP32 por dropes
[13 de Março de 2024, 21:19]


Escolher Osciloscópio por jm_araujo
[06 de Fevereiro de 2024, 23:07]


TP4056 - Dúvida por dropes
[31 de Janeiro de 2024, 14:13]


Leitura de dados por Porta Serie por jm_araujo
[22 de Janeiro de 2024, 14:00]


Distancia Cabo por jm_araujo
[08 de Janeiro de 2024, 16:30]


Meu novo robô por josecarlos
[06 de Janeiro de 2024, 16:46]


Laser Engraver - Alguém tem? por almamater
[16 de Dezembro de 2023, 14:23]


Focos LED SMD por almamater
[16 de Dezembro de 2023, 14:12]


I Belive por dropes
[15 de Dezembro de 2023, 13:59]


Carga de corrente eletrónica ZPB30A1 60W por jm_araujo
[11 de Dezembro de 2023, 13:27]

Autor Tópico: Transicão C ... C++  (Lida 4670 vezes)

0 Membros e 1 Visitante estão a ver este tópico.

Offline SerraCabo

  • Mini Robot
  • *
  • Mensagens: 1.051
    • Serra Cabo
Transicão C ... C++
« em: 19 de Janeiro de 2021, 14:58 »
Olá pessoal.

Eu tenho-me desenrascado bem programando em C mas julgo perceber que algumas funcionalidades C++ permitem coisas mais dificilmente alcançáveis em C. Deve ser por isso que o C++ foi inventado :)

Eu tenho volta e meia andado a esgravatar algumas coisas feitas (suponho) em C++, mas como mesmo receio de quem pisa terreno minado. Resumindo, preciso fazer a 'transição'.

Alguém já por aqui teve esse problema e me pode orientar com algumas indicações sobre o que ver, ler, etc? Não pretendo meter-me no insondável mundo do C++ para sistemas operativos infinitamente complicados mas tão somente o mundo dos Arduinos e afins.

Obrigado
SC

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.943
  • NERD!
Re: Transicão C ... C++
« Responder #1 em: 19 de Janeiro de 2021, 16:45 »
Versão curta: Olha só para as classes: variaveis e funcões privadas e publicas, e já ficas com um bom adianto para o que me parece que queres.

versão original:
Não sei o que recomendar, mas posso deixar uns avisos.
Para o que entendo que queres não precisas de C++ a sério (que é um biscate daqueles de trocar os olhos). Para arduinos e programação de sistemas embutidos (:D), só se costuma adicionar ao C um par de ferramentas muito úteis do C++, e o resultado é mais um "C com classes". As classes é a tal parte útil do C++, em que agrupas numa só estutura de dados as variáveis e funções que lhe dizem respeito, simplificando o código, e como disse é o que se costuma ver nos arduinos para as bibliotecas e similares. Às vezes lá aparece uma mais hard-core, mas é raro.

Das vezes que olhei para C++ mais a sério (tentar ler o Stroustrup) quando começam com namespaces, classes derivadas, templates, streams, exceptions, STL, etc fico sempre com a sensação que é areia demais para a minha camionete, só se justifica aprender a fundo se for para dar uso sério.




Offline blabla

  • Mini Robot
  • *
  • Mensagens: 257
Re: Transicão C ... C++
« Responder #2 em: 19 de Janeiro de 2021, 18:57 »
Boa tarde SerraCabo,

Concordo com tudo o que o jm_araujo disse,

Gostaria só de salientar que o C++ tem sofrido ultimamente grandes adições de features, tão grandes que existe C++ antes do C++14 e C++ depois do C++14, com o C++14, o C++17 e em 2020 com C++20 foram adicionadas tantas coisas que o C++ neste momento é uma grande confusão. É mesmo muito difícil a uma pessoa que trabalhe em C++ profissionalmente conhecer todos os cantos à casa, tanto do C++ como da STL. E depois em C++ por exemplo com templates se tiveres um erro num sitio ligado a um template, dá-te um erro nesse sitio e depois aparecem 30 ou 40 páginas de erro que não tem diretamente nada a ver com o erro no teu código, são erros indiretos de templates que dependem por vezes de um único erro muito simples. Ora isso é mesmo muito complexo para quem trabalhe normalmente em C++ quanto mais para quem só o use esporadicamente.

Tendo isto em conta um dos melhores livros de C++ (neste caso C++14 para aprender C++) é o

Programming: Principles and Practice Using C++ 2nd Edition
de Bjarne Stroustrup


Este livro ensina a programar em C++ como nenhum outro que eu conheça.

Para mais recursos free na net vê o guia:

How to learn modern C++
https://github.com/joaocarvalhoopen/How_to_learn_modern_C_Plus_Plus

Tal como jm_araujo disse tenta ver o C++ pela rama, só para cumprir o teu objectivo de programar em Arduino, pois visto a fundo é talvez a linguagem de programação mais difícil de se aprender e pouca gente sabe os cantos todos à casa.

Já para aprenderes uma boa linguagem de sistemas, de alta performance como o C++ e muito mais moderna do que o C++, muito mais segura do que o C++, sem coisas acumuladas durante 30 ou 40 anos vê Rust. Rust também pode ser usada em sistemas embebidos mas eu ainda não tenho experiencia com ela em sistemas embebidos.

How to learn modern Rust
https://github.com/joaocarvalhoopen/How_to_learn_modern_Rust

Cumprimentos,
João
« Última modificação: 19 de Janeiro de 2021, 19:03 por blabla »

Offline SerraCabo

  • Mini Robot
  • *
  • Mensagens: 1.051
    • Serra Cabo
Re: Transicão C ... C++
« Responder #3 em: 28 de Janeiro de 2021, 23:44 »
Obrigado a todos pelas dicas.

Parece-me que consegui uma luz ao fundo do túnel, usando este pequeno tutorial:
https://roboticsbackend.com/arduino-object-oriented-programming-oop/

O 'projecto' abaixo consiste em inicializar e controlar dois arrays de 2 leds:

No código-mãe(?) tenho:

Código: [Seleccione]
#include "led.h"

#define LED_1 54  //pinos
#define LED_2 55
#define LED_3 58 
#define LED_4 59

Led LedArray_1(LED_1, LED_2);  // inicializar objecto LedArray_1
Led LedArray_2(LED_3, LED_4);  // inicializar objecto LedArray_2

void setup(){
}

void loop(){
  LedArray_1.on_A();
  pause();
  LedArray_1.on_B();
  pause();
  LedArray_1.off_A();
  pause();
  LedArray_1.off_B();
  pause();

  LedArray_2.on_A();
  pause();
  LedArray_2.on_B();
  pause();
  LedArray_2.off_A();
  pause();
  LedArray_2.off_B();
  pause();
}

void pause(){
  delay(200);
}

em led.h tenho:

Código: [Seleccione]
#ifndef MY_LED_H
#define MY_LED_H

#include <Arduino.h>

class Led {
  private:
    byte Led_A;
    byte Led_B;
  public:
    Led(byte, byte);
    void init();
    void on_A();
    void off_A();
    void on_B();
    void off_B();
};

#endif

em led.cpp tenho

Código: [Seleccione]
#include "led.h"

Led::Led(byte Led_A, byte Led_B)     {
    this->Led_A=Led_A;
    this->Led_B=Led_B;
    init();
}

void Led::init(){
  pinMode(Led_A, OUTPUT);
  digitalWrite(Led_A, LOW);
  pinMode(Led_B, OUTPUT);
  digitalWrite(Led_B, LOW);
}

void Led::on_A(){
  digitalWrite(Led_A, HIGH);
}

void Led::off_A(){
  digitalWrite(Led_A, LOW);
}

void Led::on_B(){
  digitalWrite(Led_B, HIGH);
}

void Led::off_B(){
  digitalWrite(Led_B, LOW);
}

Ora bem, eu parece-me que percebo tudo menos isto:
Código: [Seleccione]
    this->Led_A=Led_A;
    this->Led_B=Led_B;

Suspeito que isto transforma os argumentos de Led::Led em variáveis públicas apenas da classe. Será o caso?

No referido tutorial eles dizem assim:
Citar
 
// Use 'this->' to make the difference between the
  // 'pin' attribute of the class and the
  // local variable 'pin' created from the parameter.

...pois, devem ter razão mas eu não percebo mas, como está, funciona.

Abraço a todos, SC
« Última modificação: 28 de Janeiro de 2021, 23:47 por SerraCabo »

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Transicão C ... C++
« Responder #4 em: 29 de Janeiro de 2021, 00:49 »
Creio que entendendo, grosso modo, o que é uma classe de C++, as coisas tornam-se mais fáceis de entender.

Uma classe em C++ é uma estrutura de dados em C (struct) e um conjunto de funções que operam implicitamente sobre essa estrutura, em que a sintaxe foi trabalhada para esconder as coisas mais feias/trabalhosas e adicionar algumas melhorias. Para isso é essencial entender ponteiros.
Podemos "simular" uma boa parte da tua classe de C++ em C (a 1ª implementação de um compilador de C++ foi um tradutor de C++ para C):

typdef struct Led {
    byte Led_A;
    byte Led_B;
};

// Método "constructor" da classe Led.
// Tive que dar um nome diferente de Led para não colidir com o nome da estrutura.
// Note-se que o 1º parametro dos métodos é um ponteiro para o objecto sobre o qual se está a operar.
void Led_ctor (Led* this, byte Led_A, byte Led_A)  {
    this->Led_A = Led_A;
    this->Led_B = Led_B;
    init(this);
}

void init (Led* this)  {
    pinMode(this->Led_A, OUTPUT);
    digitalWrite(this->Led_A, LOW);
    pinMode(this->Led_B, OUTPUT);
    digitalWrite(this->Led_B, LOW);
}

void on_A (Led* this)  {
    digitalWrite(this->Led_A, HIGH);
}

// etc para os outros métodos

main ()  {
    // Criar um objecto é criar uma variável e invocar o constructor (um objecto é uma instância duma classe):
    Led  myLed;
    Led_ctor(&myLed, 12, 13);

    on_A(&myLed);    // Invocar o método on_A()
}


Isto é uma visão simplificada mas ajuda a começar a perceber o que se passa "lá por baixo".

Depois poderemos discutir sobre o nível seguinte, como porque é que é redundante estar a prefixar A e B com "Led_" e ter A e B.
« Última modificação: 29 de Janeiro de 2021, 13:07 por Njay »

Offline jm_araujo

  • Mini Robot
  • *
  • Mensagens: 2.943
  • NERD!
Re: Transicão C ... C++
« Responder #5 em: 29 de Janeiro de 2021, 12:22 »
Boa explicação Njay. Se me permites vou fazer uma versão TLDR; , nem toda a gente se safa muito bem com apontadores em C.

O código "problemático" é:
Código: [Seleccione]
    this->Led_A=Led_A;
    this->Led_B=Led_B;

Que faz parte de:
Código: [Seleccione]
Led::Led(byte Led_A, byte Led_B)     {
    this->Led_A=Led_A;
    this->Led_B=Led_B;
    init();
}
O que acontece nesse código, é que o "Led_A" e "Led_B" passados como parâmetros da função tem o mesmo nome que as variáveis privadas da classe Led definidas em:
Código: [Seleccione]
class Led {
  private:
    byte Led_A;
    byte Led_B;

E nestes casos tem prioridade os nomes dos parâmetros da função. O "this->Led_A" o que faz é permitir aceder a essas variáveis privadas da classe, diz que em vez de aceder ao "Led_A" da função, deve aceder ao "Led_A" da classe. O "this" é uma referência a sí própria na classe.

É uma solução para um problema que pode acontecer no C com mau código: se deres o mesmo nome a um parametro duma função que a uma variável global, dentro da função não consegues aceder a essa variável global (sem usar truques).

(simplifiquei algumas coisas para facilitar o entendimento, não me crucifiquem)
(e não ficou assim tão curta, oops)
« Última modificação: 29 de Janeiro de 2021, 12:25 por jm_araujo »

Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Transicão C ... C++
« Responder #6 em: 29 de Janeiro de 2021, 13:06 »
A questão da parte "problemática" é uma questão de "scope", entendo-se o que é o "scope", que é um conceito genérico que existe em muitas (se não em todas as) linguagens, também é mais fácil perceber o resto. Também é preciso saber que dentro de um método é possível aceder às variáveis (membros) da classe, sem ter que fazer nada para isso; quando queremos aceder a elas explicitamente, temos que utilizar o nome "completo", que implica prefixar a variável (membro) com this-> . Este ponteiro para o objecto, que é um argumento implícito em todos os métodos de uma classe, tem este nome porque se refere mesmo a "este" objecto, o objecto sobre o qual se está a operar no momento.

Offline SerraCabo

  • Mini Robot
  • *
  • Mensagens: 1.051
    • Serra Cabo
Re: Transicão C ... C++
« Responder #7 em: 22 de Fevereiro de 2021, 17:09 »
Pois bem, a coisa vai avançando.

Com as indicações aqui da, como dizem os brasileiros, galera, e mais umas esgravatadelas aí pela Internet, a coisa vai andando. Escrevi 4 classes (parece que se chama assim) e fica o arrependimento de não ter entrado na transição mais cedo.

Enfim, venho aqui para carpir mágoas porque andei à chapada com o compilador porque, na declaração do objecto:

[eu acrescento uns sufixos para ver se me baralho menos]

Código: [Seleccione]
Command obCommand();
"error: request for member 'get_config' in 'obCommand', which is of non-class type 'Command()'"

... tinha que ser assim:

Código: [Seleccione]
Command obCommand;
A construção(?) desta classe não inclui (por enquanto) o envio de variáveis e o gajo não quer os parênteses. As que escrevi antes recebiam variáveis (na construção(?) e eu fiz como fazia antes, parêntesis em vazio.

Eu lia a mensagem de erro e pensava: por que diz este gajo que Command não é uma classe? ... e voltava à carga com o código da classe!

Ainda pensei que Command  pudesse ser uma palavra reservada do computador (ou da linguagem), vasculhei por aí mas nada encontrava. Cheguei a mudar-lhe o nome não fossem haver bruxas ...

Obrigado, galera, pela ajuda.
SC

Offline KammutierSpule

  • Mini Robot
  • *
  • Mensagens: 1.480
Re: Transicão C ... C++
« Responder #8 em: 23 de Fevereiro de 2021, 00:24 »
Acho que aí o problema foi confundir varias coisas.
Nesse caso aí, é igual a C, é uma declaração de uma variável:

Código: [Seleccione]
TIPO nomeVariavel;
Código: [Seleccione]
Class nomeVariavel;
Uma Class é um tipo, por isso funciona da mesma maneira que C.

uma variável na declaração não pode (suponho?) ser chamada com ( )

O que provavelmente viste foi:

Código: [Seleccione]
Class nomeVariavel = Class(parametros);
Neste caso uma Class é criada (na stack) e copiada para a nomeVariavel

Offline SerraCabo

  • Mini Robot
  • *
  • Mensagens: 1.051
    • Serra Cabo
Re: Transicão C ... C++
« Responder #9 em: 23 de Fevereiro de 2021, 01:39 »
De facto não percebo muito bem, mas tenho um caso a funcionar bem, assim:

Código: [Seleccione]
Led_arr LedArray_1(LED1_START_ENABLE_R, LED1_CONTINUE_ENABLE_R, LED1_PAUSE_ENABLE_LR, LED1_CONTINUE_ENABLE_L, LED1_START_ENABLE_L, LED1_STOP_LR);
... tudo byte


O que dava raia, era assim:

Código: [Seleccione]
Command obCommand();
Deixou de dar raia assim:
Código: [Seleccione]
Command obCommand;
O código é assim:

Código: [Seleccione]
Command::Command(){

};

O header, assim:

Código: [Seleccione]
class Command{
  public:
    Command();  // etc, etc



Tks,
Abraço



Offline Njay

  • Mini Robot
  • *
  • Mensagens: 3.598
    • Tróniquices
Re: Transicão C ... C++
« Responder #10 em: 23 de Fevereiro de 2021, 13:02 »
A mim parece que quebra o modelo, mas pelo que está aí pela net, os constructores sem parâmetros são invocados sem () .