Cara untuk berpikir tentang ini adalah dengan "berpikir seperti seorang penyusun".
Bayangkan Anda sedang menulis kompiler. Dan Anda melihat kode seperti ini.
// file: A.h
class A {
B _b;
};
// file: B.h
class B {
A _a;
};
// file main.cc
#include "A.h"
#include "B.h"
int main(...) {
A a;
}
Ketika Anda mengkompilasi file .cc (ingat bahwa .cc dan bukan .h adalah unit kompilasi), Anda perlu mengalokasikan ruang untuk objek A
. Jadi, berapa ruang yang dibutuhkan? Cukup untuk menyimpan B
! Berapa ukurannya B
? Cukup untuk menyimpan A
! Ups.
Jelas referensi melingkar yang harus Anda hancurkan.
Anda dapat memecahnya dengan membiarkan kompiler sebagai gantinya cadangan ruang sebanyak yang diketahui tentang dimuka - pointer dan referensi, misalnya, akan selalu menjadi 32 atau 64 bit (tergantung pada arsitektur) dan jadi jika Anda mengganti (salah satu) dengan sebuah penunjuk atau referensi, semuanya akan menjadi hebat. Katakanlah kita ganti A
:
// file: A.h
class A {
// both these are fine, so are various const versions of the same.
B& _b_ref;
B* _b_ptr;
};
Sekarang semuanya lebih baik. Agak. main()
masih mengatakan:
// file: main.cc
#include "A.h" // <-- Houston, we have a problem
#include
, untuk semua luasan dan tujuan (jika Anda mengeluarkan preprocessor), cukup salin file ke .cc . Jadi sungguh, .cc terlihat seperti:
// file: partially_pre_processed_main.cc
class A {
B& _b_ref;
B* _b_ptr;
};
#include "B.h"
int main (...) {
A a;
}
Anda dapat melihat mengapa kompiler tidak dapat menangani hal ini - ia tidak tahu apa B
itu - ia bahkan belum pernah melihat simbol sebelumnya.
Jadi mari kita beri tahu kompilator tentang B
. Ini dikenal sebagai deklarasi maju , dan dibahas lebih lanjut dalam jawaban ini .
// main.cc
class B;
#include "A.h"
#include "B.h"
int main (...) {
A a;
}
Ini bekerja . Itu tidak bagus . Tetapi pada titik ini Anda harus memiliki pemahaman tentang masalah referensi melingkar dan apa yang kami lakukan untuk "memperbaikinya", meskipun perbaikannya buruk.
Alasan perbaikan ini buruk adalah karena orang berikutnya #include "A.h"
harus menyatakan B
sebelum mereka dapat menggunakannya dan akan mendapatkan #include
kesalahan yang mengerikan . Jadi mari kita pindahkan deklarasi ke Ah sendiri.
// file: A.h
class B;
class A {
B* _b; // or any of the other variants.
};
Dan di Bh , pada titik ini, Anda bisa #include "A.h"
langsung.
// file: B.h
#include "A.h"
class B {
// note that this is cool because the compiler knows by this time
// how much space A will need.
A _a;
}
HTH.