Как избежать множественного включения?

103
04 февраля 2021, 17:30

Можно ли создать объект класса внутри другого класса не подключая заголовочный файл в header с описанием этого класса. сумбурно. Но вот пример.

Обычно я делаю так.

//a.h
class A
{
public:
    A();
};


//a.cpp
#include "a.h"
A::A()
{
}


//b.h
class A;
class B
{
public:
    B();
    ~B();
    A* a;
};


//b.cpp
#include "b.h"
#include "a.h"
B::B()
{
   a = new A;
}
B::~B()
{
    delete a;
}


//main.cpp
#include <a.h> // Все ок
#include <b.h> // никаких конфликтов
int main()
{
    B b;
    return 0;
}

Предварительно объявляю класс A. Создаю указатель на него в классе B, таким образом, если мне нужно подключить заголовки с этими классами к одному файлу, все ок. Но все же, можно ли создать не указатель на объект A. А объект этого класса, внутри класса B. Может есть что то эдакое. Или по крайней мере как не следить за этим объектом, если не при помощи умных указателей. Если известно, что объект класса А будет существовать на всем протяжении жизни объекта класса B.

Answer 1

Нет нельзя. Без указателей или ссылок или умных указателей не обойтись. Вообще.

Объявление типа нужно компилятору, в том числе, и для того, чтобы определить размер этого объекты в байтах, чтобы создавать объекты этого типа. Размер указателя компилятору известен, он всегда один и тот же и не зависит от типа. Поэтому чтобы создать объект B не нужно знать размер A. Если же объявить что поле B::a не указатель, а сам объект A, и не привести определение A, то размер B невозможно будет вычислить. И будет ошибка компиляции.

Answer 2

Компилятору в заголовке нужно вычислить размер класса. Если у тебя, как сейчас, указатель, он понимает, что это 4/8 байт и доволен. Сам класс A ему понадобится уже в cpp файле и включать его можно уже там. Если вы создаёте не указатель, а объект, то заголовку B нужно знать размер A. А при этом нужно включать уже в .h файле. Но ничего страшного в этом нет. Кроме весьма особых случаев, в которых преследуется цель сократить время компиляции, включать, например, заголовок a.h в b.h вполне нормально. Для избежания множественного включения стоит в начале каждого .h файла писать #pragma once и компилятор сам всё разрулит.

READ ALSO
error C3867 C++

error C3867 C++

Пишет error C3867:"std::basic_string,std::allocator>::c_str" Динамические переменные не использую, нужно отсортировать массив строк c[100] в алфавитном порядке

97
чистка проекта в линукс. configure automake

чистка проекта в линукс. configure automake

Не знаю как назвать тему вопросаВ anjuta создаю проект на gtk

121
setinterval игнорирует условие if

setinterval игнорирует условие if

Как по задумке должен работает код: "пока юзер внизу страницы функция LoadMessage обновляется и подгружает данные" и казалось бы на деле все работает,...

110
Как сделать log out

Как сделать log out

Хочу сделать logoutрегистрацию сам прописал в view а авторизацию использовал встроейный метод django

101