LINUX.ORG.RU

c++ one to many

 


0

2

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

★★★★★

Используй агрегацию по указателю/ссылке, а не по значению и неполные определения типов. Что-то вроде:

aclass.h

#ifndef ACLASS_H
#define ACLASS_H


class B;

class A {
public:
private:
    B* parent_;
};

#endif

bclass.h

#ifndef BCLASS_H
#define BCLASS_H


class A;

class B {
public:
private:
    std::vector<A*> children_;
};

#endif

Ну а в cpp-файлах просто сделаешь #include «aclass.h» и #include «bclass.h» соответственно.

m0rph ★★★★★
()
Последнее исправление: m0rph (всего исправлений: 1)
Ответ на: комментарий от Stil

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

хотя насчет инклуда в cpp файле я не подумал, форвард декларейшн в хедере, в все методы A, которые дергают методы B и, собственно, сам инклуд B сдалать в a.cpp

x0r ★★★★★
() автор топика

А вообще я бы советовал для данной задачи сделать один базовый класс, имеющий указатели на объекты своего же типа, и от него уже наследовать конкретные типы (при необходимости). Это может выглядеть например так:

class Object {
private:
    Object* parent_;
    std::vector<Object*> children_;
}

Или даже так (это если пофантазировать):

class Object {
private:
    Object* parent_;
    std::map<std::string, Object*> childByName_;
    std::string name_;
}

m0rph ★★★★★
()
Ответ на: комментарий от m0rph

дело в том, что это разные сущности, фактически Scene и Entity. городить базовый Object както совсем не то.

x0r ★★★★★
() автор топика
Ответ на: комментарий от x0r

Осспаде, я уж подумал там инлайны не разрешились. «Я познаю мир»

arturpub ★★
()

Астрологи объявили неделю C++ на лоре. Количество тредов о C++ возросло вдесятеро.

thesame ★★★★
()
Ответ на: комментарий от thesame

новый тренд, каким в свое время был лисп.

x0r ★★★★★
() автор топика
Ответ на: комментарий от x0r

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

const86 ★★★★★
()
Ответ на: комментарий от const86

В свежем libstdc++ всё обмазали всякими проверками и стлные контейнеры уже так просто не ломаются. Но самописный «без лишних наворотов» ломается на ура. Так или иначе совет в силе, пригодится, если компилятор выкатит многострочную претензию с цитатами из стлных хедеров :)

const86 ★★★★★
()

Мне кажется более логичным делать forward declaration всех классов в том же заголовке, в котором они определены.

class A;

#ifndef HEADER_A
#define HEADER_A

#include "b.h"

class A {
	B *b;
	/* ... */
};

#endif
class B;

#ifndef HEADER_B
#define HEADER_B

#include "a.h"

class B {
	A *a;
	/* ... */
};

#endif
anonymous
()
Ответ на: комментарий от andreyu

потому, что в хедере и дергается. неполный тип же.

class A;

class B {
public:
    void m() {
        a->method();
    }

private:
    A* a;
};

x0r ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Зачем? Там ведь просто декларация, Размер указателя он так вычеслит.

Boy_from_Jungle ★★★★
()
Ответ на: комментарий от x0r

В шаблон его.

А инстанциировать там, где доступны оба определения.

anonymous
()
Ответ на: комментарий от x0r

потому, что в хедере и дергается. неполный тип же.

Очевидно, что нужно вынести в cpp.

andreyu ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.