Три класса используют друг друга

Три класса: class_top->class_foo->class_bar;

class_top создает экземпляр class_foo, который далее вызывает метод class_bar. Вот код. Прошу прощения, это беспорядочно, и я думаю, что, вероятно, именно поэтому я и путаюсь.

class_bar.hpp

#ifndef TWOCLASSUSEEACHOTHER_CLASS_BAR_HPP
#define TWOCLASSUSEEACHOTHER_CLASS_BAR_HPP

#include "iostream"

namespace class_bar
{
namespace class_bar_2
{

template <typename T>
class barBase
{
public:
    barBase() = default;
    virtual void bar_print(int n) = 0; // function later gets called to add n to m_k
    void call_bar_print(int n)
    {
        bar_print(n);
    }

private:

};

class bar : public barBase <int>
{
public:
    bar() = default;
    void bar_print(int n);

private:
    int m_k = 1; // m_k initialized as 1
};

}   // class_bar_2
}   // bar

#endif //TWOCLASSUSEEACHOTHER_CLASS_BAR_HPP

class_bar.cpp

#include "../include/class_bar.hpp"
#include <iostream>

namespace class_bar
{
namespace class_bar_2
{

void bar::bar_print(int n)
{
    m_k += n;
    std::cout << "barBase printing m_k = " << m_k<< std::endl;
}

}   // class_bar2
}   // class_bar

class_foo.hpp

#ifndef TWOCLASSUSEEACHOTHER_CLASS_FOO_HPP
#define TWOCLASSUSEEACHOTHER_CLASS_FOO_HPP
#include "stdio.h"

// forward declaration
namespace class_bar
{
namespace class_bar_2
{
class bar;
}
}

using namespace class_bar::class_bar_2;

namespace class_foo
{

class foo
{
public:
    explicit foo(double dt, bar& b, int n=5, bool flag=false);
    void foo_print_from_bar(int n);

private:
    bar* m_b = NULL; // member point of class foo that points to class bar
    double m_dt;
    int m_int;
    bool m_flag;
};
}

#endif //TWOCLASSUSEEACHOTHER_CLASS_FOO_HPP

class_foo.cpp

#include "../include/class_foo.hpp"
#include "../include/class_bar.hpp"

#include <iostream>

namespace class_foo
{
foo::foo(double dt, bar& b, int n, bool flag)
        : m_dt(dt),
          m_b(&b)
{
    m_int = n;
}

void foo::foo_print_from_bar(int n)
{
    std::cout << m_dt << m_b <<m_int << m_flag;
    std::cout << "foo print using ";
    m_b->call_bar_print(n); // method of class barBase to do addition and pinting
}
}

class_top.hpp

#ifndef THREECLASSUSEEACHOTHER_CLASS_TOP_HPP
#define THREECLASSUSEEACHOTHER_CLASS_TOP_HPP
#include "class_bar.hpp"
#include "class_foo.hpp"
#include "vector"

using namespace class_bar::class_bar_2;

class top
{
public:
    top();
    void top_print(int n);
private:
    class_foo::foo m_foo;
};

#endif //THREECLASSUSEEACHOTHER_CLASS_TOP_HPP

class_top.cpp

#include "../include/class_top.hpp"

using namespace class_bar::class_bar_2;
using namespace class_foo;

void top::top_print(int n)
{
    bar b;
    foo f(3, b);
    m_foo = f;  // line where problem occurs
    m_foo.foo_print_from_bar(n);
}

main.cpp

#include "include/class_top.hpp"

int main()
{
    top* t;
    t->top_print(102); // foo calls bar to print

    return 0;
}

Не весь код здесь полезен, поэтому еще раз прошу прощения.

Код скомпилировался успешно, но при его запуске выдает строку: Process finished with exit code 139 (interrupted by signal 11:SIGSEGV);

Когда я его отлаживаю, кажется, что проблема возникает в следующей строке:

 m_foo = f;  // line where problem occurs

в class_top.cpp. Очевидно, m_foo следует использовать не так.

Пытаюсь найти, как решить эту проблему, поэтому любой указатель приветствуется. Некоторая демонстрация кода была бы очень хороша.

Какая проблема? Какую ошибку компилятора вы получаете?

Ahmed AEK 22.08.2024 17:49

«Не весь код здесь полезен, поэтому еще раз извиняюсь» — Не нужно извиняться. Просто отредактируйте вопрос и удалите все, что не имеет отношения к вопросу. См. минимально воспроизводимый пример .

Ted Lyngmo 22.08.2024 17:50

Код скомпилирован успешно, но при его запуске строка выдает «Процесс завершен с кодом выхода 139» (прерван сигналом 11:SIGSEGV); Смотрите обновление из темы.

Nick X Tsui 22.08.2024 17:51

Показанный код не может скомпилироваться.

3CxEZiVlQ 22.08.2024 17:52

@TedLyngmo ОК. Позвольте мне попробовать.

Nick X Tsui 22.08.2024 17:53
top* t; t->top_print(102); здесь t не инициализирован, указывает на мусор, включите предупреждения компилятора, чтобы отловить это.
Ahmed AEK 22.08.2024 17:53

@AhmedAEK, как мне это изменить?

Nick X Tsui 22.08.2024 17:55

уберите звездочку top t; ... на этом этапе я должен порекомендовать хорошую книгу по C++, если вы не знаете, как работают указатели.

Ahmed AEK 22.08.2024 18:01

Чтобы задать вопрос, могли бы вы предоставить код без вложенных пространств имен? Такое ощущение, что просто еще больше шума мешает обнаружить проблему.

Chris 22.08.2024 18:30

Предложение: замените NULL на nullptr.

Chris 22.08.2024 18:37

@NickXTsui Re: «ОК. Дай мне попробовать» — внесенное вами редактирование не привело к созданию минимального воспроизводимого примера.

Ted Lyngmo 22.08.2024 18:48

Также прочитайте о висячих указателях, вы получите адрес переменной bar b; и сохраните его в члене m_foo. Этот адрес станет недействительным после выхода из функции top::top_print().

sklott 22.08.2024 18:55
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
12
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Корень вашей ошибки в том, что в main() этот код вызывает неопределенное поведение во время выполнения:

top* t;
t->top_print(102);

Вы вызываете top_print() недопустимый top объект через неинициализированный указатель. Это означает, что top_print() попытается получить доступ к объекту m_foo, которого нет в памяти.

Вместо этого используйте это:

top t;
t.top_print(102);

При этом создается реальный объект top, а затем вызывается top_print() к нему.


При этом в вашем коде есть и ряд других проблем:

  • Вам следует прочитать В чем разница между #include <имя файла> и #include «имя файла»?

    • Вместо class_bar.hpp#include "iostream" должно быть #include <iostream>. Однако ничто в этом .hpp файле не ссылается напрямую на iostream, поэтому вы можете просто удалить это #include вообще. У вас уже есть соответствующий #include в class_bar.cpp, где ему и место.

    • В class_foo.hpp вместо #include "stdio.h" должно быть #include <stdio.h> или лучше #include <cstdio>. Однако вам следует использовать nullptr вместо NULL, поэтому вы можете просто удалить этот #include.

    • Вместо class_top.hpp#include "vector" должно быть #include <vector>. Однако top не использует std::vector, поэтому вы можете просто удалить это #include.

  • в class_bar.hpp и class_foo.hpp не рекомендуется использовать операторы using namespace внутри файлов заголовков, если они не находятся внутри других namespace. Но вместо этого вы используете операторы using в глобальной области видимости. Не следует загрязнять глобальное пространство имен.

  • В class_top.cpp отсутствует определение конструктора top, что приведет к неразрешенной внешней ошибке.

    Член top::m_foo имеет тип foo, а foo имеет конструктор, отличный от стандартного, что означает, что конструктор top должен инициализировать m_foo, используя свой собственный список инициализации членов , чтобы он мог передавать параметры конструктору m_foo. Это означает, что конструктору top необходим доступ к объекту bar, который переживет m_foo, поскольку m_foo будет содержать указатель на этот bar объект. Таким образом, вам следует передать параметр bar& конструктору top, чтобы он затем мог передать его конструктору foo, например:

    class top
    {
    public:
        top(bar& b);
         void top_print(int n);
    private:
        class_foo::foo m_foo;
    };
    
    top::top(bar& b)
        : m_foo(3, b) // <-- HERE
    {
    }
    
    void top::top_print(int n)
    {
        m_foo.foo_print_from_bar(n);
    }
    

    Это означает, что main() нужен объект bar для передачи конструктору top:

    bar b; // <-- HERE
    top t(b);
    t.top_print(102);
    
  • строка m_foo = f; компилируется нормально. Поскольку foo не определяет явно конструктор копирования или назначение копирования operator= для себя, компилятор автоматически сгенерирует их для вас. А реализации по умолчанию просто копируют значения всех членов данных из одного объекта foo в другой. В этом случае член foo::m_b может быть проблематичным, в зависимости от того, кто на самом деле владеет объектом bar. Так что будьте осторожны с этим.

    В данном конкретном примере это нормально, поскольку указатель bar* не является указателем-владельцем. Но если бы это был указатель владения, у вас были бы проблемы, если бы вы не следовали правилу 3/5/0 в реализации foo.

С учетом всего вышесказанного, вот онлайн-демонстрация, которая решает все проблемы, упомянутые выше:

https://onlinegdb.com/8cwnxE1uLs

Теперь это имеет большой смысл. Огромное спасибо, Реми, за терпение и объяснения!

Nick X Tsui 22.08.2024 18:56

Реми просто терпелив. Посмотрите, как долго ему пришлось ждать, чтобы сняться в достойном фильме.

user4581301 22.08.2024 19:17

@ user4581301 ха-ха :-)

Remy Lebeau 22.08.2024 20:00

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