Objective-C: Forward Class Declaration
It basically tells the compiler that the class RootViewController
exists, without specifying what exactly it looks like (ie: its methods, properties, etc). You can use this to write code that includes RootViewController
member variables without having to include the full class declaration.
This is particularly useful in resolving circular dependencies - for example, where say ClassA
has a member of type ClassB*
, and ClassB
has a member of type ClassA*
. You need to have ClassB
declared before you can use it in ClassA
, but you also need ClassA
declared before you can use it in ClassB
. Forward declarations allow you to overcome this by saying to ClassA
that ClassB
exists, without having to actually specify ClassB's
complete specification.
Another reason you tend to find lots of forward declarations is some people adopt a convention of forward declaring classes unless they absolutely must include the full declaration. I don't entirely recall, but possibly that's something that Apple recommends in it's Objective-C guiding style guidlines.
Continuing my above example, if your declarations of ClassA
and ClassB
are in the files ClassA.h
and ClassB.h
respectively, you'd need to #import
whichever one to use its declaration in the other class. Using forward declaration means you don't need the #import
, which makes the code prettier (particularly once you start collecting quite a few classes, each of which would need an `#import where it's used), and increases compiling performance by minimising the amount of code the compiler needs to consider while compiling any given file.
As an aside, although the question is concerned solely with forward declarations in Objective-C, all the proceeding comments also apply equally to coding in C and C++ (and probably many other languages), which also support forward declaration and typically use it for the same purposes.
C++ class forward declaration
In order for new T
to compile, T
must be a complete type. In your case, when you say new tile_tree_apple
inside the definition of tile_tree::tick
, tile_tree_apple
is incomplete (it has been forward declared, but its definition is later in your file). Try moving the inline definitions of your functions to a separate source file, or at least move them after the class definitions.
Something like:
class A
{
void f1();
void f2();
};
class B
{
void f3();
void f4();
};
inline void A::f1() {...}
inline void A::f2() {...}
inline void B::f3() {...}
inline void B::f4() {...}
When you write your code this way, all references to A and B in these methods are guaranteed to refer to complete types, since there are no more forward references!
Forward declaration of objective-c class extension method
An extension's interface is like any other for purposes of method visibility: the compiler has to see the declaration before the use.* Unfortunately, you will have to put the @interface
either into a header or further up in the file than Foo
's implementation.
*The one exception to this that I know of is for methods that are not named in an interface at all -- essentially declared by their definition -- and used within the same @implementation
block. The compiler will figure that out for you regardless of the order.
Class Forward Declaration C++
Forward declaration is not enough, you have to make some change on the StockObserver::StockGrabber(StockObserver so) member functions' signature, because if you pass the argument by value you need the definition not only the declaration of the parameters' class. If you pass by reference, then the declaration is enough for declaring the function, but that declaration is not surely enough for implement that function, so may be you will have to define the function outside of the class after StockObserver class defintion. Look at the code below, an it will be more understandable.
class Subject{ /* ... */ };
class Observer{ /* ... */ };
class StockObserver;
class StockGrabber: public Subject {
//...
//the constructor involves a StockObserver object
StockGrabber(StockObserver& so); // class StockObserver is declared before StockGrabber::StockGrabber(StockObserver&).
};
class StockObserver: public Observer {
//...
StockObserver(StockGrabber sg) { /* ... */ };
};
StockGrabber::StockGrabber(StockObserver& so){ /* ... */ } // class StockObserver is defined before StockGrabber::StockGrabber(StockObserver&).
What are forward declarations in C++?
Why forward-declare is necessary in C++
The compiler wants to ensure you haven't made spelling mistakes or passed the wrong number of arguments to the function. So, it insists that it first sees a declaration of 'add' (or any other types, classes, or functions) before it is used.
This really just allows the compiler to do a better job of validating the code and allows it to tidy up loose ends so it can produce a neat-looking object file. If you didn't have to forward declare things, the compiler would produce an object file that would have to contain information about all the possible guesses as to what the function add
might be. And the linker would have to contain very clever logic to try and work out which add
you actually intended to call, when the add
function may live in a different object file the linker is joining with the one that uses add to produce a dll
or exe
. It's possible that the linker may get the wrong add
. Say you wanted to use int add(int a, float b)
, but accidentally forgot to write it, but the linker found an already existing int add(int a, int b)
and thought that was the right one and used that instead. Your code would compile, but wouldn't be doing what you expected.
So, just to keep things explicit and avoid guessing, etc, the compiler insists you declare everything before it is used.
Difference between declaration and definition
As an aside, it's important to know the difference between a declaration and a definition. A declaration just gives enough code to show what something looks like, so for a function, this is the return type, calling convention, method name, arguments, and their types. However, the code for the method isn't required. For a definition, you need the declaration and then also the code for the function too.
How forward-declarations can significantly reduce build times
You can get the declaration of a function into your current .cpp
or .h
file by #includ'ing the header that already contains a declaration of the function. However, this can slow down your compile, especially if you #include
a header into a .h
instead of .cpp
of your program, as everything that #includes the .h
you're writing would end up #include'ing all the headers you wrote #includes for too. Suddenly, the compiler has #included pages and pages of code that it needs to compile even when you only wanted to use one or two functions. To avoid this, you can use a forward-declaration and just type the declaration of the function yourself at the top of the file. If you're only using a few functions, this can really make your compiles quicker compared to always #including the header. For really large projects, the difference could be an hour or more of compile time bought down to a few minutes.
Break cyclic references where two definitions both use each other
Additionally, forward-declarations can help you break cycles. This is where two functions both try to use each other. When this happens (and it is a perfectly valid thing to do), you may #include
one header file, but that header file tries to #include
the header file you're currently writing... which then #includes the other header, which #includes the one you're writing. You're stuck in a chicken and egg situation with each header file trying to re #include the other. To solve this, you can forward-declare the parts you need in one of the files and leave the #include out of that file.
Eg:
File Car.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
File Wheel.h
Hmm... the declaration of Car
is required here as Wheel
has a pointer to a Car
, but Car.h
can't be included here as it would result in a compiler error. If Car.h
was included, that would then try to include Wheel.h
which would include Car.h
which would include Wheel.h
and this would go on forever, so instead the compiler raises an error. The solution is to forward declare Car
instead:
class Car; // forward declaration
class Wheel
{
Car* car;
};
If class Wheel
had methods which need to call methods of Car
, those methods could be defined in Wheel.cpp
and Wheel.cpp
is now able to include Car.h
without causing a cycle.
Forward Declaration of Class: Syntax Error
Forward declarations are fine for resolving pointer and reference types in declarations.
However, the compiler needs the complete definition of the types when compiling functions.
What is forward declaration in c++?
Chad has given a pretty good dictionary definition. Forward declarations are often used in C++ to deal with circular relationships. For example:
class B; // Forward declaration
class A
{
B* b;
};
class B
{
A* a;
};
When can I use a forward declaration?
Put yourself in the compiler's position: when you forward declare a type, all the compiler knows is that this type exists; it knows nothing about its size, members, or methods. This is why it's called an incomplete type. Therefore, you cannot use the type to declare a member, or a base class, since the compiler would need to know the layout of the type.
Assuming the following forward declaration.
class X;
Here's what you can and cannot do.
What you can do with an incomplete type:
Declare a member to be a pointer or a reference to the incomplete type:
class Foo {
X *p;
X &r;
};Declare functions or methods which accept/return incomplete types:
void f1(X);
X f2();Define functions or methods which accept/return pointers/references to the incomplete type (but without using its members):
void f3(X*, X&) {}
X& f4() {}
X* f5() {}
What you cannot do with an incomplete type:
Use it as a base class
class Foo : X {} // compiler error!
Use it to declare a member:
class Foo {
X m; // compiler error!
};Define functions or methods using this type
void f1(X x) {} // compiler error!
X f2() {} // compiler error!Use its methods or fields, in fact trying to dereference a variable with incomplete type
class Foo {
X *m;
void method()
{
m->someMethod(); // compiler error!
int i = m->someField; // compiler error!
}
};
When it comes to templates, there is no absolute rule: whether you can use an incomplete type as a template parameter is dependent on the way the type is used in the template.
For instance, std::vector<T>
requires its parameter to be a complete type, while boost::container::vector<T>
does not. Sometimes, a complete type is required only if you use certain member functions; this is the case for std::unique_ptr<T>
, for example.
A well-documented template should indicate in its documentation all the requirements of its parameters, including whether they need to be complete types or not.
How to translate @class forward declaration to Swift?
You Cannot always ignore the @class
forward declarations if you do not own the code.
'Bug' Report:
I work with an Objective-C library that is consumed as an opaque third-party framework, with only the header files exposed. When errors occur, the framework generates and vends a MyError
object to a delegate. So far, so good.
Since the developer using the framework never creates an object of this class, it is not exposed, but no worries; since it is forward-declared, it's fine -- in ObjC! But Swift does not have Forward Declarations, and the object was ignored in Swift files that rely on the ObjC framework. In this case, no MyError
object means no error reporting!
Workaround
I worked around the issue by redeclaring it in a Swift file, e.g. "MyError+Workaround.swift".
import Foundation
class MyError: NSError {} // the object actually is an NSError subclass
That's it. Hope this helps someone else out there.
Update
We fixed the code by explicitly adding the class in the umbrella header; coding contortions no longer needed.
Related Topics
Why Does Storing References (Not Pointers) in Containers in C++ Not Work
How to Make Elements of Vector Unique? (Remove Non Adjacent Duplicates)
Should We Generally Use Float Literals for Floats Instead of the Simpler Double Literals
So Why Is I = ++I + 1 Well-Defined in C++11
Vector of Std::Function with Different Signatures
How to Alloc a Executable Memory Buffer
Is There a Portable Equivalent to Debugbreak()/_Debugbreak
Does Casting to an Int After Std::Floor Guarantee the Right Result
Using Export Keyword with Templates
How to Make 'New[]' Default-Initialize the Array of Primitive Types
Qt/C++ - Accessing Mainwindow UI from a Different Class
Reason Why Not to Have a Delete MACro for C++
Is There a 128 Bit Integer in C++