два класса создают друг друга, не могут использовать предварительные объявления

У меня есть классы A и B с обоими заголовочными файлами с включенными охранниками. Один читает:

#ifndef A_H
#define A_H

#include "B.h"
class A
{
B b;
};

#endif

И другой:

#ifndef B_H
#define B_H

#include "A.h"
class B
{
A a;
};

#endif

Теперь я проверяю это с помощью main.cpp:

#include "A.h"
int main()
{
A a;
}

Ошибка компиляции выглядит следующим образом:

# make main
g++     main.cpp   -o main
B.h:8: error: ‘A’ does not name a type

Есть ли какое-либо решение этой ситуации, кроме использования указателя / ссылки и предварительного объявления?

1

Решение

Нет, это невозможно: один из них должен быть указателем или ссылкой: потому что если A содержит B, который содержит A, который содержит B, то у вас бесконечная рекурсия и вы пытаетесь указать объект бесконечного размера.

4

Другие решения

Нет, к сожалению, нет другого варианта, кроме как использовать указатель / ссылку и прямое объявление.

2

Вы не можете этого сделать, вы бы вызвали бесконечную рекурсию (A будет включать B, B будет включать, A …), плюс компилятор не допустит этого, потому что в одном из объявлений класса другой класс будет неполным , (Не полностью определено)

Вы можете просто сделать это, если один из них является указателем или ссылкой.

1

Я предлагаю использовать идиому pImpl, если это возможно (указатель на реализацию, другие имена: непрозрачный указатель, идиома тела-ручки, чеширский кот … см. Вот для деталей. )

Это в основном позволяет вам «освободить» объявление вашего класса от деталей реализации, которые обычно видны пользователям вашего класса (даже если они не используются, если private доступ).

Вы просто объявляете свой класс следующим образом:

#ifndef A_H
#define A_H

class A{
public:
//declare public methods -> "interface"private:
struct Private;
Private * mp_d;  //feel free to use smart pointer
};

#endif

Форвард объявил struct (или же class ) определяется только в вашем исходном файле и содержит все детали реализации, такие как члены данных и функции, которые являются внутренними для вашего класса.

#include "B.h"struct A::Private {
B a;
};A::A() : mp_d( new Private()) {
}

A::~A(){
delete mp_d;   //not required if using smart pointer
}

NB: Теперь созданный компилятором конструктор копирования и операторы присваивания больше не работают (как и ожидалось). Убедитесь, что реализовали их самостоятельно или просто запретили компилятору генерировать их, объявив их private (без реализации). (Это в основном стиль C ++ 03; я считать в C ++ 11 вы просто добавляете = deleteпосле объявления, чтобы предотвратить генерацию компилятора.)

РЕДАКТИРОВАТЬ: добавлено «длинное» имя pImpl

1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector