Три класса: 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 следует использовать не так.
Пытаюсь найти, как решить эту проблему, поэтому любой указатель приветствуется. Некоторая демонстрация кода была бы очень хороша.
«Не весь код здесь полезен, поэтому еще раз извиняюсь» — Не нужно извиняться. Просто отредактируйте вопрос и удалите все, что не имеет отношения к вопросу. См. минимально воспроизводимый пример .
Код скомпилирован успешно, но при его запуске строка выдает «Процесс завершен с кодом выхода 139» (прерван сигналом 11:SIGSEGV); Смотрите обновление из темы.
Показанный код не может скомпилироваться.
@TedLyngmo ОК. Позвольте мне попробовать.
top* t; t->top_print(102);
здесь t
не инициализирован, указывает на мусор, включите предупреждения компилятора, чтобы отловить это.
@AhmedAEK, как мне это изменить?
уберите звездочку top t;
... на этом этапе я должен порекомендовать хорошую книгу по C++, если вы не знаете, как работают указатели.
Чтобы задать вопрос, могли бы вы предоставить код без вложенных пространств имен? Такое ощущение, что просто еще больше шума мешает обнаружить проблему.
Предложение: замените NULL
на nullptr
.
@NickXTsui Re: «ОК. Дай мне попробовать» — внесенное вами редактирование не привело к созданию минимального воспроизводимого примера.
Также прочитайте о висячих указателях, вы получите адрес переменной bar b;
и сохраните его в члене m_foo
. Этот адрес станет недействительным после выхода из функции top::top_print()
.
Корень вашей ошибки в том, что в 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
Теперь это имеет большой смысл. Огромное спасибо, Реми, за терпение и объяснения!
Реми просто терпелив. Посмотрите, как долго ему пришлось ждать, чтобы сняться в достойном фильме.
@ user4581301 ха-ха :-)
Какая проблема? Какую ошибку компилятора вы получаете?