0

Following up on this question C++ inheritence and array I have a question about derived classes and their methods.

Currently I have this base class

class FunctionBlock
{
public:
    uint8_t  IN1 : 1 ;
    uint8_t  IN2 : 1 ;
    uint8_t  IN3 : 1 ;
    uint8_t    Q : 1 ;
} ; 

And several derived classes. These are just three out of many

class And : public FunctionBlock
{
public:
    And()
    {
        IN1 = IN2 = IN3 = 1 ;
    }
    void run()
    {
        Q = IN1 & IN2 & IN3 ;
    }
} ;

class Input : public FunctionBlock
{
public:

    Input( uint8_t _pin )
    {
        pin = _pin ;
        pinMode( pin, INPUT_PULLUP ) ;
    }

    uint8_t pin ;

    void run()
    {
        Q = digitalRead( pin ) ;
    }
} ;

class Output : public FunctionBlock
{
public:
    Output ( uint8_t _pin )
    {
        pin = _pin ;
        pinMode( pin, OUTPUT ) ;
    }

    uint8_t pin ;

    void run()
    {
        digitalWrite( pin, IN2 ) ;
    }
} ;

Every last derived class has a run() method.

I made an array of these derived classes and I initialized them.

FunctionBlock *block[ nBlocks ]; 
  
void setup()
{
    block[0] = & Input(1);
    block[1] = & Input(2);
    block[2] = & Input(3);
    block[3] = & And() ;
    block[4] = & Output(4) ;
}

Until so far everything compiles just fine.

But now the problem. I want to run the run() method of every object in the array. Like I said before every object has it's own run() method.

In the main loop() I try this code

void loop()
{
/***************** UPDATE FUNCTION BLOCKS *****************/
    for( int i = 0 ; i < nBlocks ; i ++ ) block[i] -> run() ;

/***************** UPDATE LINKS *****************/
    block[3]->IN2 = block[1]->Q ;  // this compiles
    block[3]->IN1 = block[0]->Q ;
    block[3]->IN3 = block[2]->Q ;
    block[4]->IN2 = block[3]->Q ;
} ;

And that tosses me the following error.

arduinoProgram:153:55: error: 'class FunctionBlock' has no member named 'run'

     for( int i = 0 ; i < nBlocks ; i ++ ) block[i] -> run() ;

                                                       ^~~

I understand what is happening. The main class does not have a run() method. Only the derived classes do. But the array itself is of the main class FunctionBlocks and thus has no acces to the different run() methods.

My question: Is there a construct in C++ with which an array of objects can get access to methods of derived classes? Like I am trying to do in my example

(I compile this program avr-gcc compiler)

EDIT: Despite my lack of knowdledge about object pointers. I have also resolved the memory problem by first declaring the static derived objects and than create the 'functionBlock'array.

#include "functionBlocks.h"

static Input  b1 = Input(1) ;
static Input  b2 = Input(2) ;
static Input  b3 = Input(3) ;
static Or     b4 = Or() ;
static Delay  b5 = Delay( 3000 ) ;
static Output b6 = Output(13) ;

const int nBlocks = 6 ;

FunctionBlock *block[] =
{
    &b1,
    &b2,
    &b3,
    &b4,
    &b5,
    &b6,
} ;

void setup()
{
}

void loop()
{
    block[3] -> IN1 = block[0] -> Q ;
    block[3] -> IN2 = block[1] -> Q ;
    block[3] -> IN3 = block[2] -> Q ;
    block[4] -> IN2 = block[3] -> Q ;
    block[5] -> IN2 = block[4] -> Q ;

/***************** UPDATE FUNCTION BLOCKS *****************/
    for( int i = 0 ; i < nBlocks ; i ++ ) block[i] -> run() ;
} ;

The program now also actually works.

bask185
  • 377
  • 1
  • 3
  • 12
  • 1
    The `setup` function stores a bunch of pointers to temporary objects that are immediately destroyed. – Retired Ninja Sep 22 '22 at 23:35
  • Thanks. I already noticed that my program is not doing what it must. I moved the lines to the `void loop()`. But this pointer misery is not making me happy today. How do I solve this particular 'feature' – bask185 Sep 22 '22 at 23:41
  • 1
    Even if you moved it to `loop`, it's still not going to work. You need to store all those `Input` and `And` and `Output` somewhere, OR allocate them using `new` or `std::unique_ptr`. Otherwise you have undefined behaviour. – Brandon Sep 22 '22 at 23:47
  • 1
    @RetiredNinja The code shouldn't even compile, as it is illegal to take the address of temporary objects. – Remy Lebeau Sep 22 '22 at 23:54
  • I do not understand why the objects are temporary. I declared them in the global scope. I will read in and try to use new – bask185 Sep 23 '22 at 07:13

1 Answers1

0

I tried the following

class FunctionBlock
{
public:
    uint8_t  IN1 : 1 ;
    uint8_t  IN2 : 1 ;
    uint8_t  IN3 : 1 ;
    uint8_t    Q : 1 ;

    virtual void run() ;
} ; 

The virtual keyword seems to do the trick.

bask185
  • 377
  • 1
  • 3
  • 12
  • 1
    Yes, you do indeed want a [`virtual`](https://en.cppreference.com/w/cpp/language/virtual) function. You also really need a [good book](https://stackoverflow.com/q/388242/212858) to explain basic concepts. – Useless Sep 22 '22 at 23:39
  • This solves the immediate problems of the the loop not being able to call derived class `run()` methods. But it does not solve the issue of bad lifetime management of the derived object instances, which the code also suffers from. – Remy Lebeau Sep 22 '22 at 23:55
  • And no visible implementation of the base class `run` function. – Retired Ninja Sep 22 '22 at 23:59