Как создать два класса в C ++, которые используют друг друга в качестве данных? - PullRequest
39 голосов
/ 11 февраля 2011

Я хочу создать два класса, каждый из которых содержит объект другого типа.Как я могу это сделать?Если я не могу сделать это, есть ли обходной путь, например, чтобы каждый класс содержал указатель на другой тип класса?Спасибо!

Вот что у меня есть:

Файл: bar.h

#ifndef BAR_H
#define BAR_H
#include "foo.h"
class bar {
public:
  foo getFoo();
protected:
  foo f;
};
#endif

Файл: foo.h

#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo {
public:
  bar getBar();
protected:
  bar b;
};
#endif

Файл: main.cpp

#include "foo.h"
#include "bar.h"

int
main (int argc, char **argv)
{
  foo myFoo;
  bar myBar;
}

$ g ++ main.cpp

In file included from foo.h:3,
                 from main.cpp:1:
bar.h:6: error: ‘foo’ does not name a type
bar.h:8: error: ‘foo’ does not name a type

Ответы [ 3 ]

93 голосов
/ 11 февраля 2011

У вас не может быть двух классов, которые напрямую содержат объекты другого типа, так как в противном случае вам понадобится бесконечное пространство для объекта (так как в foo есть строка с элементом foo, в котором есть строка и т.* Вы действительно можете сделать это, если два класса хранят указатели друг на друга.Для этого вам нужно использовать предварительные объявления , чтобы два класса знали о существовании друг друга:

#ifndef BAR_H
#define BAR_H

class foo; // Say foo exists without defining it.

class bar {
public:
  foo* getFoo();
protected:
  foo* f;
};
#endif 

и

#ifndef FOO_H
#define FOO_H

class bar; // Say bar exists without defining it.

class foo {
public:
  bar* getBar();
protected:
  bar* f;
};
#endif 

Обратите вниманиедва заголовка не включают друг друга.Вместо этого они просто знают о существовании другого класса через предварительные объявления.Затем в файлах .cpp для этих двух классов вы можете #include другой заголовок, чтобы получить полную информацию о классе.Эти предварительные объявления позволяют вам разорвать ссылочный цикл "foo needs bar needs foo needs bar."

4 голосов
/ 11 февраля 2011

Это не имеет смысла.Если A содержит B, а B содержит A, это будет бесконечный размер.Представьте, что вы кладете две коробки и пытаетесь положить обе в другую.Не работает, верно?

Хотя указатели работают:

#ifndef FOO_H
#define FOO_H

// Forward declaration so the compiler knows what bar is
class bar;

class foo {
public:
  bar *getBar();
protected:
  bar *b;
};
#endif
0 голосов
/ 31 августа 2018

Правильно, просто добавлю,

описанные выше методы позволят вам иметь указатели только на указанные классы.

В своих путешествиях я обнаружил, что функция, которая создает экземпляр класса с указателем на него, также может быть выполнена (изображение кода, фактический код в конце) :

code and running

Здесь вы включаете заголовок из класса, который вы «порождаете», чтобы компилятор имел актуальную информацию о нем и, таким образом, мог его создать.

Конечно, это также позволяет вам иметь экземпляр B внутри A (изображение кода, фактический код в конце) :

b inside of a kappa

Возможно, вы также можете подумать о некоторых других вещах kewl, gn.


Код без изображения

Пример 1

хиджры

#pragma once

#include "b.h"

struct A {
    char aye, beye, ceye;
    B createB(unsigned val);
};

a.cpp

#include "a.h"

B A::createB(unsigned val){
    return {69, this};
}

b.h

#pragma once

struct A;

struct B {
    unsigned ellel;
    A* dad;
    B& printOurEllel();
};

b.cpp

#include <stdio.h>
#include "b.h"

B& B::printOurEllel(){
    printf("ellel: %d\n", this->ellel);
    return *this;
}

основной

#include <stdio.h>

#include "a.h"
#include "b.h"


int main() {
    A elgay = { 1, 2, 3 };
    printf("%d\n", elgay.createB(69).printOurEllel().dad->beye);
    getchar();
}

результат

ellel: 69
2

Пример 2

хиджры

#pragma once

#include "b.h"

struct A {
    char aye, beye, ceye;
    B yeetos;
};

b.h

#pragma once

struct A;

struct B {
    unsigned ellel;
    A* dad;
    B& printOurEllel();
};

b.cpp

#include <stdio.h>
#include "b.h"

B& B::printOurEllel(){
    printf("ellel: %d\n", this->ellel);
    return *this;
}  

основной :

#include <stdio.h>

#include "a.h"
#include "b.h"


int main() {
    A elgay = { 1, 2, 3, {69, &elgay} };
    printf("%d\n", elgay.yeetos.printOurEllel().dad->beye);
    getchar();
}

результат

ellel: 69
2
...