Вызов метода ученика из определения родительского класса

Я создаю ЖК-меню, и у меня проблемы с взаимодействием lcdmenu (главное меню) и submenu.

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)
{
}

Я передаю список экземпляров submenu в переменную lcdmenu.submenulist и хочу lcdmenu::render() вызвать lcd_string(submenulist[index]->get_text());, но не могу использовать submenu.get_text, если этот метод еще не определен.

Есть ли способ отформатировать мой файл, чтобы я мог использовать как полностью определенный класс lcdmenu, так и submenu классы друг в друге?

Что вы подразумеваете под «методом студента»? Вы имели в виду «метод подкласса»?

Barmar 20.06.2024 19:36

Если у вас публичное наследование без виртуальных функций, возможно, вы делаете что-то не так.

n. m. could be an AI 20.06.2024 20:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете использовать метод класса до его объявления.

Использование прямого объявления — правильный способ устранения циклических ссылок между классами. Итак, то, что вы делаете для члена lcdmenu::submenulist (и, предположительно, то же самое для члена lcdmenu::commandlist), вполне подходит для объявления класса lcdmenu.

Но предварительное объявление не помогает реализации метода lcdmenu::render(). Для доступа к его членам требуется полное объявление класса submenu, например метод submenu::get_text() (и то же самое с классом command).

Итак, вам нужно разделить ваши объявления и реализации на отдельные файлы .h и .cpp, чтобы облегчить эту задачу, например:

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()); 
        }

подменю.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

подменю.cpp

#include "submenu.h"

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

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

команда.h

#ifndef command_H
#define command_H

...

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

#endif

команда.cpp

#include "command.h"

...

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

Теперь при компиляции lcdmenu.cpp компилятор после замен препроцессора увидит следующий код:

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()); 
        }

И когда вы скомпилируете submenu.cpp, компилятор после замен препроцессора увидит следующий код:

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;
}

И когда вы скомпилируете command.cpp, компилятор после замен препроцессора увидит следующий код:

...

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

...

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

Это идеально, спасибо!

Andy Votava 20.06.2024 20:20

Рад, что это помогает. Теперь, пожалуйста, прочтите Что мне делать, если кто-то отвечает на мой вопрос?

Remy Lebeau 20.06.2024 20:32

Сделаю! Я получаю ошибку компиляции: когда я включаю lcdmenu.cpp в add_executable() моего файла cmake, я получаю ошибку multiple definition, но когда я удаляю его из функции, я получаю ошибку undefined reference. (также у меня недостаточно репутации, чтобы проголосовать, извините)

Andy Votava 20.06.2024 20:39

Тогда вы скорее всего что-то не правильно настроили при разделении. Но это следует опубликовать как новый вопрос с минимально воспроизводимым примером.

Remy Lebeau 20.06.2024 20:57

Другие вопросы по теме