Search code examples
c++arduinoinner-classes

How can I instantiate C++ class A in the constructor of class B such that its object is available to the member functions


Most of my background is in Python and I am trying to re-learn C++ as it applies to micro-controller boards like Arduino.

I have created a standalone C++ class named DigitalGPIOPin. I also have another class named DigitalRGBPin that will need to instantiate 3 objects of the DigitalGPIOPin class in the constructor and share access to the objects with its member functions. Is this possible with C++?

I am attaching my attempt at this problem thus far with a simplified case, but I get the error shown below the code, which indicates that the member function initialize_rgb_pin() can not access the objects.

// GPIOPin.hpp file
class DigitalGPIOPin
{
public:
    int id;  // Pin identifier
    int io   // INPUT or OUTPUT
    DigitalGPIOPin(int identifier, int io_type);
    void initialize_pin();
};
// -----------------------------------------------------------------

class DigitalRGBPin
{
public:
    int red_id, green_id, blue_id
    DigitalRGBPin(int red_identifier, int green_identifier, int blue_identifier);
    void initialize_rgb_pin();
};
// =================================================================
// =================================================================

// GPIOPin.cpp file
DigitalGPIOPin::DigitalGPIOPin(int identifier, int io_type)
{
    id = identifier;
    io = io_type;
}

void
DigitalGPIOPin::initialize_pin()
{
    if (io == OUTPUT || io == INPUT || io == INPUT_PULLUP) {
        pinMode(id, io);
    }
    else {
        Serial.println("Pin mode not recognized");
    }
}
// -----------------------------------------------------------------

DigitalRGBPin::DigitalRGBPin(int red_identifier, int green_identifier, int blue_identifier)
{
    red_id = red_identifier;
    green_id = green_identifier;
    blue_id = blue_identifier;
    DigitalGPIOPin red_pin(red_identifier, OUTPUT);
    DigitalGPIOPin green_pin(green_identifier, OUTPUT);
    DigitalGPIOPin blue_pin(blue_identifier, OUTPUT);
}
// -----------------------------------------------------------------

void
DigitalRGBPin::initialize_rgb_pin()
{
    red_pin.initialize_pin();
    /* Commented out lines below to focus on problem.
       The compiler does not recognize red_pin, because it
       was not defined as a public variable.  So how can I
       define this without having to re-write the entire
       DigitalGPIOPin class as a nested class within DigitalRGBPin.
       This would effectively put me in a position where I have to define
       the class twice, since I still need it as a standalone class. 
    */
    // green_pin.initialize_pin();
    // blue_pin.initialize_pin();
}

This yields the following error:

error: red_pin was not declared in this scope


Solution

  • You have declared red_pin, green_pin, and blue_pin as local variables inside of your DigitalRGBPin() constructor. As such, the compiler error is correct - they are not in scope for initialize_rgb_pin() (or any other method of DigitalRGBPin) to access.

    You need to make them be members of the DigitalRGBPin class (just as you did for id and io in the DigitalGPIOPin class, and red_id, green_id, blue_id in the DigitalRGBPin class).

    However, you will have to use the DigitalRGBPin() constructor's member initialization list to initialize them 1, since DigitalGPIOPin doesn't have a default constructor defined.

    1: you should get in the habit of using the member initialization list for all of your classes when it is feasible to do so.

    Try this:

    GPIOPin.hpp

    class DigitalGPIOPin
    {
    public:
        int id;  // Pin identifier
        int io;  // INPUT or OUTPUT
        DigitalGPIOPin(int identifier, int io_type);
        void initialize_pin();
    };
    // -----------------------------------------------------------------
        
    class DigitalRGBPin
    {
    public:
        int red_id, green_id, blue_id;
        DigitalGPIOPin red_pin, green_pin, blue_pin;
        DigitalRGBPin(int red_identifier, int green_identifier, int blue_identifier);
        void initialize_rgb_pin();
    };
    // =================================================================
    // =================================================================
    

    GPIOPin.cpp

    DigitalGPIOPin::DigitalGPIOPin(int identifier, int io_type) :
        id(identifier),
        io(io_type)
    {
    }
    
    void DigitalGPIOPin::initialize_pin()
    {
        if (io == OUTPUT || io == INPUT || io == INPUT_PULLUP) {
            pinMode(id, io);
        }
        else {
            Serial.println("Pin mode not recognized");
        }
    }
    // -----------------------------------------------------------------
        
    DigitalRGBPin::DigitalRGBPin(int red_identifier, int green_identifier, int blue_identifier) :
        red_id(red_identifier),
        green_id(green_identifier),
        blue_id(blue_identifier),
        red_pin(red_identifier, OUTPUT),
        green_pin(green_identifier, OUTPUT),
        blue_pin(blue_identifier, OUTPUT)
    {
    }
    // -----------------------------------------------------------------
    
    void DigitalRGBPin::initialize_rgb_pin()
    {
        red_pin.initialize_pin();
        green_pin.initialize_pin();
        blue_pin.initialize_pin();
    }
    

    On a side note, the red_id, green_id, and blue_id members of the DigitalRGBPin class are redundant, and thus can (and should) be removed in favor of using red_pin.id, green_pin.id, and blue_pin.id when needed, eg:

    GPIOPin.hpp

    class DigitalGPIOPin
    {
    public:
        int id;  // Pin identifier
        int io;  // INPUT or OUTPUT
        DigitalGPIOPin(int identifier, int io_type);
        void initialize_pin();
    };
    // -----------------------------------------------------------------
        
    class DigitalRGBPin
    {
    public:
        DigitalGPIOPin red_pin, green_pin, blue_pin;
        DigitalRGBPin(int red_identifier, int green_identifier, int blue_identifier);
        void initialize_rgb_pin();
    };
    // =================================================================
    // =================================================================
    

    GPIOPin.cpp

    DigitalGPIOPin::DigitalGPIOPin(int identifier, int io_type) :
        id(identifier),
        io(io_type)
    {
    }
    
    void DigitalGPIOPin::initialize_pin()
    {
        if (io == OUTPUT || io == INPUT || io == INPUT_PULLUP) {
            pinMode(id, io);
        }
        else {
            Serial.println("Pin mode not recognized");
        }
    }
    // -----------------------------------------------------------------
        
    DigitalRGBPin::DigitalRGBPin(int red_identifier, int green_identifier, int blue_identifier) :
        red_pin(red_identifier, OUTPUT),
        green_pin(green_identifier, OUTPUT),
        blue_pin(blue_identifier, OUTPUT)
    {
    }
    // -----------------------------------------------------------------
    
    void DigitalRGBPin::initialize_rgb_pin()
    {
        red_pin.initialize_pin();
        green_pin.initialize_pin();
        blue_pin.initialize_pin();
    }