I know that I can do:
class Foo;
but can I forward declare a class as inheriting from another, like:
class Bar {};
class Foo: public Bar;
An example use case would be co-variant reference return types.
// somewhere.h
class RA {}
class RB : public RA {}
... and then in another header that doesn't include somewhere.h
// other.h
class RA;
class A {
public:
virtual RA* Foo(); // this only needs the forward deceleration
}
class RB : public RA; // invalid but...
class B {
public:
virtual RB* Foo(); //
}
The only information the compiler should need to process the declaration of RB* B:Foo() is that RB has RA as a public base class. Now clearly you would need somewhere.h if you intend to do any sort of dereferencing of the return values from Foo. However, if some clients never calls Foo, then there is no reason for them to include somewhere.h which might significantly speed compilation.
A forward declaration is only really useful for telling the compiler that a class with that name does exist and will be declared and defined elsewhere. You can't use it in any case where the compiler needs contextual information about the class, nor is it of any use to the compiler to tell it only a little bit about the class. (Generally, you can only use the forward declaration when referring to that class without other context, e.g. as a parameter or return value.)
Thus, you can't forward declare Bar in any scenario where you then use it to help declare Foo, and it flat-out doesn't make sense to have a forward declaration that includes the base class -- what does that tell you besides nothing?
Forward declarations are declarations, not definitions. So, anything that requires the declaration of a class (like pointers to that class) need only the forward declaration. However, anything that would require the definition - i.e. would need to know the actual structure of the class - would not work with just the forward declaration.
Derived classes definitely need to know the structure of their parent, not just that the parent exists, so a forward declaration would be insufficient.
No it is not possible to forward declare inheritance, even if you are only dealing with pointers. When dealing with conversions between pointers, sometimes the compiler has to know the details of the class to do the conversion correctly. This is the case with multiple inheritance. (You could special case some parts parts of the hierarchy that only use single inheritance, but that isn't part of the language.)
Consider the following trivial case:
#include <stdio.h>
class A { int x; };
class B { int y; };
class C: public A, public B { int z; };
void main()
{
C c; A *pa = &c; B *pb = &c; C *pc = &c;
printf("A: %p, B: %p, C: %p\n", pa, pb, pc);
}
The output I received (using 32 bit visual studio 2010), is:
A: 0018F748, B: 0018F74C, C: 0018F748
So for multiple inheritance, when converting between related pointers, the compiler has to insert some pointer arithmetic to get the conversions right.
This is why, even if you are dealing only with pointers, you can't forward declare inheritance.
As for why it would be useful, it would improve compile times when you do want to make use of co-variant return types instead of using casts. For example this will not compile:
class RA;
class A { public: virtual RA *fooRet(); };
class RB;
class B : public A { public: virtual RB *fooRet(); };
But this will:
class RA;
class A { public: virtual RA *fooRet(); };
class RA { int x; };
class RB : public RA{ int y; };
class B : public A { public: virtual RB *fooRet(); };
This is useful when you have objects of type B (not pointers or references). In this case the compiler is smart enough to use a direct function call, and you can use the return type of RB* directly without casting. In this case, usually I go ahead and make the return type RA * and do a static cast on the return value.
All you needed to do was declare RB without the : public RA (oh, and also add ; to the end of your class definitions):
class RA;
class A {
public:
virtual RA* Foo();
};
class RB;
class B {
public:
virtual RB* Foo();
};
// client includes somewhere.h
class RA {};
class RB : public RA {};
int main ()
{
return 0;
}
However, this doesn't solve the specific problem described nicely in the answer by user1332054.
Some of the other answers appear to show some misconceptions that I'd like to dispel:
Forward declaring is useful even when when we know that the definition is not likely to be included. This allows us to do a lot of type-deduction in our libraries that make them compatible with many other established libraries without including them. Including libraries unnecessarily leads to too many nested includes that can explode the compile time. It's good practice to make your code compatible when appropriate, and to include as little as possible.
Typically you can define a class with pointers to classes that have only been declared and not defined. Example:
struct B;
struct A
{
B * b_;
B * foo ()
{
return b_;
}
B & foo (B * b)
{
return *b;
}
};
int main ()
{
return 0;
}
The above compiles fine, because the compiler doesn't need to know anything about B.
An example where it might be a bit harder to realise that the compiler needs more information:
struct B;
struct A
{
B * foo ()
{
return new B;
}
};
The above problem is because new B invokes the B::B() constructor which hasn't been defined yet. Also:
struct B;
struct A
{
void foo (B b) {}
};
Here foo must call the copy constructor for b, which also hasn't been defined yet. Lastly:
struct B;
struct A
{
B b;
};
Here we have implicitly defined A with the default constructor, which calls the default constructor of call its members,b, which hasn't been defined yet. I think' you get the point.
So, in reference to the more general problem, described by user1332054, I honestly don't understand why it's not possible to use pointers to undefined classed in an inherited virtual function.
More broadly though, I think that you're making it more difficult for yourself by defining your classes instead of only declaring them. Here's an example where you get to DoCleverStuff with your classes in your library before you've defined any of your classes at all:
// Just declare
class RA;
class RB;
class A;
class B;
// We'll need some type_traits, so we'll define them:
template <class T>
struct is_type_A
{
static constexpr bool value = false;
};
template <>
struct is_type_A <A>
{
static constexpr bool value = true;
};
template <class T>
struct is_type_B
{
static constexpr bool value = false;
};
template <>
struct is_type_B <B>
{
static constexpr bool value = true;
};
#include <type_traits>
// With forward declarations, templates and type_traits now we don't
// need the class definitions to prepare useful code:
template<class T>
typename std::enable_if<is_type_A<T>::value, RA *>::type
DoCleverStuff (T & t)
{
// specific to A
return t.fooRet();
}
template<class T>
typename std::enable_if<is_type_B<T>::value, RB *>::type
DoCleverStuff (T & t)
{
// specific to B
return t.fooRet();
}
// At some point the user *does* the include:
class RA
{
int x;
};
class RB : public RA
{
int y;
};
class A
{
public:
virtual RA * fooRet()
{
return new RA;
}
};
class B : public A
{
public:
virtual RB * fooRet()
{
return new RB;
}
};
int main ()
{
// example calls:
A a;
RA * ra = DoCleverStuff(a);
B b;
RB * rb = DoCleverStuff(b);
delete ra;
delete rb;
return 0;
}
I don't think it's useful. Consider: you have defined a class, Bar:
class Bar {
public:
void frob();
};
Now you declare a class Foo:
class Foo;
All you can do with Foo is construct a pointer to it. Now, suppose you add the information that Foo is derived from Bar:
class Foo: public Bar;
What can you now do that you couldn't do before? I think that all you can do is accept a pointer to Foo and cast it into a pointer to Bar, then use that pointer.
void frob(Foo* f) {
Bar *b = (Bar)f;
b->frob();
}
However, you must have generated the pointer elsewhere, so you could have just accepted a pointer to Bar instead.
void frob(Bar* b) {
b->frob();
}
Related
I know that I can do:
class Foo;
but can I forward declare a class as inheriting from another, like:
class Bar {};
class Foo: public Bar;
An example use case would be co-variant reference return types.
// somewhere.h
class RA {}
class RB : public RA {}
... and then in another header that doesn't include somewhere.h
// other.h
class RA;
class A {
public:
virtual RA* Foo(); // this only needs the forward deceleration
}
class RB : public RA; // invalid but...
class B {
public:
virtual RB* Foo(); //
}
The only information the compiler should need to process the declaration of RB* B:Foo() is that RB has RA as a public base class. Now clearly you would need somewhere.h if you intend to do any sort of dereferencing of the return values from Foo. However, if some clients never calls Foo, then there is no reason for them to include somewhere.h which might significantly speed compilation.
A forward declaration is only really useful for telling the compiler that a class with that name does exist and will be declared and defined elsewhere. You can't use it in any case where the compiler needs contextual information about the class, nor is it of any use to the compiler to tell it only a little bit about the class. (Generally, you can only use the forward declaration when referring to that class without other context, e.g. as a parameter or return value.)
Thus, you can't forward declare Bar in any scenario where you then use it to help declare Foo, and it flat-out doesn't make sense to have a forward declaration that includes the base class -- what does that tell you besides nothing?
Forward declarations are declarations, not definitions. So, anything that requires the declaration of a class (like pointers to that class) need only the forward declaration. However, anything that would require the definition - i.e. would need to know the actual structure of the class - would not work with just the forward declaration.
Derived classes definitely need to know the structure of their parent, not just that the parent exists, so a forward declaration would be insufficient.
No it is not possible to forward declare inheritance, even if you are only dealing with pointers. When dealing with conversions between pointers, sometimes the compiler has to know the details of the class to do the conversion correctly. This is the case with multiple inheritance. (You could special case some parts parts of the hierarchy that only use single inheritance, but that isn't part of the language.)
Consider the following trivial case:
#include <stdio.h>
class A { int x; };
class B { int y; };
class C: public A, public B { int z; };
void main()
{
C c; A *pa = &c; B *pb = &c; C *pc = &c;
printf("A: %p, B: %p, C: %p\n", pa, pb, pc);
}
The output I received (using 32 bit visual studio 2010), is:
A: 0018F748, B: 0018F74C, C: 0018F748
So for multiple inheritance, when converting between related pointers, the compiler has to insert some pointer arithmetic to get the conversions right.
This is why, even if you are dealing only with pointers, you can't forward declare inheritance.
As for why it would be useful, it would improve compile times when you do want to make use of co-variant return types instead of using casts. For example this will not compile:
class RA;
class A { public: virtual RA *fooRet(); };
class RB;
class B : public A { public: virtual RB *fooRet(); };
But this will:
class RA;
class A { public: virtual RA *fooRet(); };
class RA { int x; };
class RB : public RA{ int y; };
class B : public A { public: virtual RB *fooRet(); };
This is useful when you have objects of type B (not pointers or references). In this case the compiler is smart enough to use a direct function call, and you can use the return type of RB* directly without casting. In this case, usually I go ahead and make the return type RA * and do a static cast on the return value.
All you needed to do was declare RB without the : public RA (oh, and also add ; to the end of your class definitions):
class RA;
class A {
public:
virtual RA* Foo();
};
class RB;
class B {
public:
virtual RB* Foo();
};
// client includes somewhere.h
class RA {};
class RB : public RA {};
int main ()
{
return 0;
}
However, this doesn't solve the specific problem described nicely in the answer by user1332054.
Some of the other answers appear to show some misconceptions that I'd like to dispel:
Forward declaring is useful even when when we know that the definition is not likely to be included. This allows us to do a lot of type-deduction in our libraries that make them compatible with many other established libraries without including them. Including libraries unnecessarily leads to too many nested includes that can explode the compile time. It's good practice to make your code compatible when appropriate, and to include as little as possible.
Typically you can define a class with pointers to classes that have only been declared and not defined. Example:
struct B;
struct A
{
B * b_;
B * foo ()
{
return b_;
}
B & foo (B * b)
{
return *b;
}
};
int main ()
{
return 0;
}
The above compiles fine, because the compiler doesn't need to know anything about B.
An example where it might be a bit harder to realise that the compiler needs more information:
struct B;
struct A
{
B * foo ()
{
return new B;
}
};
The above problem is because new B invokes the B::B() constructor which hasn't been defined yet. Also:
struct B;
struct A
{
void foo (B b) {}
};
Here foo must call the copy constructor for b, which also hasn't been defined yet. Lastly:
struct B;
struct A
{
B b;
};
Here we have implicitly defined A with the default constructor, which calls the default constructor of call its members,b, which hasn't been defined yet. I think' you get the point.
So, in reference to the more general problem, described by user1332054, I honestly don't understand why it's not possible to use pointers to undefined classed in an inherited virtual function.
More broadly though, I think that you're making it more difficult for yourself by defining your classes instead of only declaring them. Here's an example where you get to DoCleverStuff with your classes in your library before you've defined any of your classes at all:
// Just declare
class RA;
class RB;
class A;
class B;
// We'll need some type_traits, so we'll define them:
template <class T>
struct is_type_A
{
static constexpr bool value = false;
};
template <>
struct is_type_A <A>
{
static constexpr bool value = true;
};
template <class T>
struct is_type_B
{
static constexpr bool value = false;
};
template <>
struct is_type_B <B>
{
static constexpr bool value = true;
};
#include <type_traits>
// With forward declarations, templates and type_traits now we don't
// need the class definitions to prepare useful code:
template<class T>
typename std::enable_if<is_type_A<T>::value, RA *>::type
DoCleverStuff (T & t)
{
// specific to A
return t.fooRet();
}
template<class T>
typename std::enable_if<is_type_B<T>::value, RB *>::type
DoCleverStuff (T & t)
{
// specific to B
return t.fooRet();
}
// At some point the user *does* the include:
class RA
{
int x;
};
class RB : public RA
{
int y;
};
class A
{
public:
virtual RA * fooRet()
{
return new RA;
}
};
class B : public A
{
public:
virtual RB * fooRet()
{
return new RB;
}
};
int main ()
{
// example calls:
A a;
RA * ra = DoCleverStuff(a);
B b;
RB * rb = DoCleverStuff(b);
delete ra;
delete rb;
return 0;
}
I don't think it's useful. Consider: you have defined a class, Bar:
class Bar {
public:
void frob();
};
Now you declare a class Foo:
class Foo;
All you can do with Foo is construct a pointer to it. Now, suppose you add the information that Foo is derived from Bar:
class Foo: public Bar;
What can you now do that you couldn't do before? I think that all you can do is accept a pointer to Foo and cast it into a pointer to Bar, then use that pointer.
void frob(Foo* f) {
Bar *b = (Bar)f;
b->frob();
}
However, you must have generated the pointer elsewhere, so you could have just accepted a pointer to Bar instead.
void frob(Bar* b) {
b->frob();
}
Suppose I have the class
class A {
protected:
int x,y;
double z,w;
public:
void foo();
void bar();
void baz();
};
defined and used in my code and the code of others. Now, I want to write some library which could very well operate on A's, but it's actually more general, and would be able to operate on:
class B {
protected:
int y;
double z;
public:
void bar();
};
and I do want my library to be general, so I define a B class and that's what its APIs take.
I would like to be able to tell the compiler - not in the definition of A which I no longer control, but elsewhere, probably in the definition of B:
Look, please try to think of B as a superclass of A. Thus, in particular, lay it out in memory so that if I reinterpret an A* as a B*, my code expecting B*s would work. And please then actually accept A* as a B* (and A& as a B& etc.).
In C++ we can do this the other way, i.e. if B is the class we don't control we can perform a "subclass a known class" operation with class A : public B { ... }; and I know C++ doesn't have the opposite mechanism - "superclass a known class A by a new class B". My question is - what's the closest achievable approximation of this mechanism?
Notes:
This is all strictly compile-time, not run-time.
There can be no changes whatsoever to class A. I can only modify the definition of B and code that knows about both A and B. Other people will still use class A, and so will I if I want my code to interact with theirs.
This should preferably be "scalable" to multiple superclasses. So maybe I also have class C { protected: int x; double w; public: void baz(); } which should also behave like a superclass of A.
You can do the following:
class C
{
struct Interface
{
virtual void bar() = 0;
virtual ~Interface(){}
};
template <class T>
struct Interfacer : Interface
{
T t;
Interfacer(T t):t(t){}
void bar() { t.bar(); }
};
std::unique_ptr<Interface> interface;
public:
template <class T>
C(const T & t): interface(new Interfacer<T>(t)){}
void bar() { interface->bar(); }
};
The idea is to use type-erasure (that's the Interface and Interfacer<T> classes) under the covers to allow C to take anything that you can call bar on and then your library will take objects of type C.
I know C++ doesn't have the opposite mechanism - "superclass a known
class"
Oh yes it does:
template <class Superclass>
class Class : public Superclass
{
};
and off you go. All at compile time, needless to say.
If you have a class A that can't be changed and need to slot it into an inheritance structure, then use something on the lines of
template<class Superclass>
class Class : public A, public Superclass
{
};
Note that dynamic_cast will reach A* pointers given Superclass* pointers and vice-versa. Ditto Class* pointers. At this point, you're getting close to Composition, Traits, and Concepts.
Normal templates do this, and the compiler will inform you when you use them incorrectly.
instead of
void BConsumer1(std::vector<B*> bs)
{ std::for_each(bs.begin(), bs.end(), &B::bar); }
void BConsumer2(B& b)
{ b.bar(); }
class BSubclass : public B
{
double xplusz() const { return B::x + B::z; }
}
you write
template<typename Blike>
void BConsumer1(std::vector<Blike*> bs)
{ std::for_each(bs.begin(), bs.end(), &Blike::bar); }
template<typename Blike>
void BConsumer2(Blike& b)
{ b.bar(); }
template<typename Blike>
class BSubclass : public Blike
{
double xplusz() const { return Blike::x + Blike::z; }
}
And you use BConsumer1 & BConsumer2 like
std::vector<A*> as = /* some As */
BConsumer1(as); // deduces to BConsumer1<A>
A a;
BConsumer2(a); // deduces to BConsumer2<A>
std::vector<B*> bs = /* some Bs */
BConsumer1(bs); // deduces to BConsumer1<B>
// etc
And you would have BSubclass<A> and BSubclass<B>, as types that use the B interface to do something.
There is no way to change the behaviour of a class without changing the class. There is indeed no mechanism for adding a parent class after A has already been defined.
I can only modify the definition of B and code that knows about both A and B.
You cannot change A, but you can change the code that uses A. So you could, instead of using A, simply use another class that does inherit from B (let us call it D). I think this is the closest achievable of the desired mechanism.
D can re-use A as a sub-object (possibly as a base) if that is useful.
This should preferably be "scalable" to multiple superclasses.
D can inherit as many super-classes as you need it to.
A demo:
class D : A, public B, public C {
public:
D(const A&);
void foo(){A::foo();}
void bar(){A::bar();}
void baz(){A::baz();}
};
Now D behaves exactly as A would behave if only A had inherited B and C.
Inheriting A publicly would allow getting rid of all the delegation boilerplate:
class D : public A, public B, public C {
public:
D(const A&);
};
However, I think that could have potential to create confusion between code that uses A without knowledge of B and code that uses knows of B (and therefore uses D). The code that uses D can easily deal with A, but not the other way 'round.
Not inheriting A at all but using a member instead would allow you to not copy A to create D, but instead refer to an existing one:
class D : public B, public C {
A& a;
public:
D(const A&);
void foo(){a.foo();}
void bar(){a.bar();}
void baz(){a.baz();}
};
This obviously has potential to mistakes with object lifetimes. That could be solved with shared pointers:
class D : public B, public C {
std::shared_ptr<A> a;
public:
D(const std::shared_ptr<A>&);
void foo(){a->foo();}
void bar(){a->bar();}
void baz(){a->baz();}
};
However, this is presumably only an option if the other code that doesn't know about Bor D also uses shared pointers.
This seems more like static polymorphism rather dynamic. As #ZdeněkJelínek has already mentioned, you could you a template to ensure the proper interface is passed in, all during compile-time.
namespace details_ {
template<class T, class=void>
struct has_bar : std::false_type {};
template<class T>
struct has_bar<T, std::void_t<decltype(std::declval<T>().bar())>> : std::true_type {};
}
template<class T>
constexpr bool has_bar = details_::has_bar<T>::value;
template<class T>
std::enable_if_t<has_bar<T>> use_bar(T *t) { t->bar(); }
template<class T>
std::enable_if_t<!has_bar<T>> use_bar(T *) {
static_assert(false, "Cannot use bar if class does not have a bar member function");
}
This should do what you'd like (i.e. use bar for any class) without having to resort to a vtable lookup and without having the ability to modify classes. This level of indirection should be inlined out with proper optimization flags set. In other words you'll have the runtime efficiency of directly invoking bar.
Given a base class Base that has two derived classes, DerA and DerB, can the derived classes have a member variable that is used in a Base member function, but is a different type for each class?
class Base {
* a // Declare a as *something*, so it can be used by "doWork"
template <typedef T>
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base {
// Make "a" an int
}
class DerB : public Base {
// Make "a" a float
}
In practice, a will be a base struct, while DerA and DerB will have derived versions of the base struct (derivative classes will each have a derived form of the struct specific to their purpose, but each must do a simple operation on a, so it seems pointless to copy/paste that simple function for each derivative when I can just use a template function). I would just type a as the base struct type, but then I lose access to the various specialized member functions and variables that each derived struct has (if I understand inheritance correctly).
I apologize if this question is a repeat, but I don't know what this quality would be called, so Googling proved fruitless.
What you might want is the CRTP.
template<class D>
struct Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork(T b) {
self()->a += b;
}
};
struct DerA : public Base<DerA> {
int a;
};
struct DerB : public Base<DerB> {
double a;
};
Here we pass the derived type to our base class. Within the base class, you can use self()-> to access fields in the derived type. This allows basically full access to the derived type, while letting us share code in the base class.
Note that you cannot pass DerA and DerB around as a Base this way. If you want that, you need a virtual method doWork, and virtual template methods don't exist.
CRTP stands for the curiously repeating template pattern, which I imagine is named because it is strange, it involves repeating a type, and it keeps on showing up in strange corners as being useful.
Type erasure probably won't work either, as you want to dispatch the type erasure from two different spots in the code base (the double dispatch problem: you need a centralized list of types supported to do the type Cartesian product on).
To expand on that, in order to support a+=b where both a and b are arbitrary types, you would have to expand over all types twice over, including types that are never mutually visible at the same spot in a compilation unit. That isn't possible.
If you need a common base, and there are only some types you pass to doWork, here is how you do it:
struct Base {
virtual void doWork( double ) = 0;
virtual void doWork( int ) = 0;
virtual void doWork( long long ) = 0;
};
template<class D>
struct Base_helper:Base {
D* self() { return static_cast<D*>(this); }
D const* self() const { return static_cast<D*>(this); }
template<class T>
void doWork_impl(T b) {
self()->a += b;
}
void doWork( double x ) override { doWork_impl(x); };
void doWork( int x ) override { doWork_impl(x); };
void doWork( long long x ) override { doWork_impl(x); };
};
struct DerA : public Base_helper<DerA> {
int a;
};
struct DerB : public Base_helper<DerB> {
double a;
};
note that every version of doWork must be valid to call on each of the Ders, as the Base_helper instantiates all of them.
If the kind of type passed to doWork is unbounded, yet the types of Der is bounded, you can do something like the above only backwards. It gets awkward, however. Your best bet in that kind of situation is to use a boost::variant type solution.
I guess you want to achieve something like this:
template<typedef T>
class Base {
T a;
void doWork(T b) { // Add another value to "a" which is of its same type
a += b; // For example; an operation that works on "a", no matter what numeric type it is
}
}
class DerA : public Base<int> {
}
class DerB : public Base<float> {
}
Or you can dump classes DerA and DerB entirely and use typedefs instead:
typedef Base<int> DerA;
typedef Base<float> DerB;
This can be easily solved with a CRTP-like pattern:
template<class D> // Base class is templated
class Base {
public:
D a;
void doWork(D b) {
a += b;
}
};
class DerA : public Base<int> {};
class DerB : public Base<float> {};
Live Example
Edit: in case you need only one common base (Base<int> is a completely different type from Base<float>) you might use an interface class and have Base inherit from it.
I have two classes in separate headers:
struct A {
virtual B getB();
}
template<typename T>
struct Basic : public A {
}
typedef Basic<int> B;
Both headers need to include each other, which is not ideal due to circular dependency.
However, A::getB() returns an instance, so I can't forward declare to avoid the include, and Basic inherits A, so its the same deal there. Basic must inherit A, but A doesn't NEED the getB() function (although, it is highly preferable).
I must avoid the circular dependency, but am I going about this the wrong way?
Note: the A class will be inherited by a lot of other classes further down the line, hence why getB() is virtual. And Basic is a template class, so it's definition is inside it's header as well. getB() must return an instance (anything coming out of getB() is expected to be local to getB(), which is why it can't return a pointer nor a reference).
You can forward declare if you are returning by value.
So in your example, you'd have to do the following:
template <typename> struct Basic;
typedef Basic<int> B;
struct A {
virtual B getB();
};
do the following:
struct A {
virtual B* getB();
}
That is, struct A must refer to struct B only through pointers. Then you can solve the issue by forward declaring struct B before the definition of struct A.
Update After Clarification:
You can do something like the following then:
template <typename> struct Basic;
typedef Basic<int> B;
struct A {
virtual B getB();
};
template<typename T>
struct Basic : public A {
};
// definitions of member functions for struct A below here!!!
B A::getB() { B b; return b;}
int main()
{
A a;
B b;
return 0;
}
Have in mind though that definitions of member functions for struct A must be under definition of struct B.
Is there anyway to declare an object of a class before the class is created in C++? I ask because I am trying to use two classes, the first needs to have an instance of the second class within it, but the second class also contains an instance of the first class. I realize that you may think I might get into an infinite loop, but I actually need to create and instance of the second class before the first class.
You can't do something like this:
class A {
B b;
};
class B {
A a;
};
The most obvious problem is the compiler doesn't know how to large it needs to make class A, because the size of B depends on the size of A!
You can, however, do this:
class B; // this is a "forward declaration"
class A {
B *b;
};
class B {
A a;
};
Declaring class B as a forward declaration allows you to use pointers (and references) to that class without yet having the whole class definition.
You can't declare an instance of an undefined class but you can declare a pointer to one:
class A; // Declare that we have a class A without defining it yet.
class B
{
public:
A *itemA;
};
class A
{
public:
B *itemB;
};
There's an elegant solution using templates.
template< int T > class BaseTemplate {};
typedef BaseTemplate< 0 > A;
typedef BaseTemplate< 1 > B;
// A
template<> class BaseTemplate< 0 >
{
public:
BaseTemplate() {} // A constructor
B getB();
}
// B
template<> class BaseTemplate< 1 >
{
public:
BaseTemplate() {} // B constructor
A getA();
}
inline B A::getB() { return A(); }
inline A B::getA() { return B(); }
This code will work! So, why does it
work? The reason has to do with how
templates are compiled. Templates
delay the creation of function
signatures until you actually use the
template somewhere. This means that
neither getA() nor getB() will have
their signatures analyzed until after
both classes A and B have already been
fully declared. That's the magic of
this method.
Is this close to what you want: The first class contains the second class, but the second class (that is to be created first) just has a reference to the first class?
This is called cross reference. See here an example.