c++classoopinheritanceraspberry-pi-pico

Calling student method from parent class definition


I'm making an LCD menu and having trouble with the lcdmenu (main menu) and submenu interaction.

class submenu;

class lcdmenu
{
protected:
    command **commandlist;
    submenu **submenulist;
    ...   

public:
    void setchildren(command **comlist, submenu **sublist, int comn, int subn);
    void render();
    ...

};

void lcdmenu::render(){
    lcd_clear();
    for (int line = 0; line < MAX_LINES; line ++){
        int index = menutop + line;
        ...

        if (index < numcommands){
            lcd_string(commandlist[index]->get_text());
            lcd_string(submenulist[index]->get_text()); 
        }
class submenu : public lcdmenu {
public:
    lcdmenu *parent;
    submenu(lcdmenu *par, const char* text);

    const char* get_text(){
        return text;
    }
};

submenu::submenu(lcdmenu *par, const char* text_):text(text_), parent(par)
{
}

I am passing a list of submenu instances into the lcdmenu.submenulist variable, and I want lcdmenu::render() to call lcd_string(submenulist[index]->get_text()); but I can not use submenu.get_text when that method has not been defined yet.

Is there a way to format my file so I can use both the fully defined lcdmenu class and submenu classes within each other?


Solution

  • You can't use a class method before it has been declared.

    Using a forward declaration is the correct way to address circular references between classes. So what you are doing for the lcdmenu::submenulist member (and presumably the same for the lcdmenu::commandlist member) is perfectly fine for the purpose of declaring the lcdmenu class.

    But, the forward declaration does not help the implementation of the lcdmenu::render() method. It needs the full declaration of the submenu class in order to access its members, such as the submenu::get_text() method (and the same with the command class).

    So, you need to split up your declarations and implementations into separate .h and .cpp files to help facilitate this task, eg:

    lcdmenu.h

    #ifndef lcdmenu_H
    #define lcdmenu_H
    
    class command;
    class submenu;
    
    class lcdmenu
    {
    protected:
        command **commandlist;
        submenu **submenulist;
        ...   
    
    public:
        void setchildren(command **comlist, submenu **sublist, int comn, int subn);
        void render();
        ...
    };
    
    #endif
    

    lcdmenu.cpp

    #include "lcdmenu.h"
    #include "submenu.h"
    #include "command.h"
    ...
    
    void lcdmenu::render(){
        lcd_clear();
        for (int line = 0; line < MAX_LINES; line ++){
            int index = menutop + line;
            ...
    
            if (index < numcommands){
                lcd_string(commandlist[index]->get_text());
                lcd_string(submenulist[index]->get_text()); 
            }
    

    submenu.h

    #ifndef submenu_H
    #define submenu_H
    
    #include "lcdmenu.h"
    
    class submenu : public lcdmenu {
    public:
        lcdmenu *parent;
        submenu(lcdmenu *par, const char* text);
    
        const char* get_text();
    };
    
    #endif
    

    submenu.cpp

    #include "submenu.h"
    
    submenu::submenu(lcdmenu *par, const char* text_):text(text_), parent(par)
    {
    }
    
    const char* submenu::get_text(){
        return text;
    }
    

    command.h

    #ifndef command_H
    #define command_H
    
    ...
    
    class command ... {
    public:
        ...
        const char* get_text();
    };
    
    #endif
    

    command.cpp

    #include "command.h"
    
    ...
    
    const char* command::get_text(){
        return ...;
    }
    

    Now, when you compile lcdmenu.cpp, the compiler will see the following code after preprocessor substitutions:

    class command;
    class submenu;
    
    class lcdmenu
    {
    protected:
        command **commandlist;
        submenu **submenulist;
        ...   
    
    public:
        void setchildren(command **comlist, submenu **sublist, int comn, int subn);
        void render();
        ...
    };
    
    class submenu : public lcdmenu {
    public:
        lcdmenu *parent;
        submenu(lcdmenu *par, const char* text);
    
        const char* get_text();
    };
    
    ...
    class command ... {
    public:
        ...
        const char* get_text();
    };
    
    ...
    
    void lcdmenu::render(){
        lcd_clear();
        for (int line = 0; line < MAX_LINES; line ++){
            int index = menutop + line;
            ...
    
            if (index < numcommands){
                lcd_string(commandlist[index]->get_text());
                lcd_string(submenulist[index]->get_text()); 
            }
    

    And when you compile submenu.cpp, the compiler will see the following code after preprocessor substitutions:

    class command;
    class submenu;
    
    class lcdmenu
    {
    protected:
        command **commandlist;
        submenu **submenulist;
        ...   
    
    public:
        void setchildren(command **comlist, submenu **sublist, int comn, int subn);
        void render();
        ...
    };
    
    class submenu : public lcdmenu {
    public:
        lcdmenu *parent;
        submenu(lcdmenu *par, const char* text);
    
        const char* get_text();
    };
    
    submenu::submenu(lcdmenu *par, const char* text_):text(text_), parent(par)
    {
    }
    
    const char* submenu::get_text(){
        return text;
    }
    

    And when you compile command.cpp, the compiler will see the following code after preprocessor substitutions:

    ...
    
    class command ... {
    public:
        ...
        const char* get_text();
    };
    
    ...
    
    const char* command::get_text(){
        return ...;
    }