Forward Declarations¶
Goal: Minimize compile-time dependencies
When to Forward Declare¶
✅ DO Forward Declare When:¶
1. Pointer or Reference Member
// header.hpp
class EventDispatcher; // Forward declaration
class MyClass {
EventDispatcher* dispatcher_; // Pointer - OK
};
2. Pointer or Reference Parameter
class Parameter; // Forward declaration
void process_parameter(Parameter& param); // Reference - OK
void set_parameter(Parameter* param); // Pointer - OK
3. Return Type (Pointer/Reference)
class Buffer; // Forward declaration
Buffer* get_buffer(); // Pointer return - OK
Buffer& get_buffer_ref(); // Reference return - OK
❌ DON'T Forward Declare When:¶
1. Value Member
#include "parameter.hpp" // MUST include
class MyClass {
Parameter param_; // Value member - needs complete type
};
2. Inheritance
#include "base_class.hpp" // MUST include
class Derived : public BaseClass { // Inheritance - needs complete type
};
3. Template Parameter
#include "processor.hpp" // MUST include
std::vector<Processor> processors_; // Template - needs complete type
4. Using Member Functions/Data
#include "buffer.hpp" // MUST include
void foo(Buffer& buf) {
buf.resize(100); // Using methods - needs complete type
}
Proper Forward Declaration Syntax¶
Classes¶
Templates¶
Nested Classes¶
Example: Minimize Dependencies¶
Bad (Includes Everything)¶
// my_processor.hpp
#include "event_dispatcher.hpp" // Full include
#include "parameter.hpp" // Full include
#include "buffer.hpp" // Full include
class MyProcessor {
EventDispatcher* dispatcher_; // Could use forward declaration
Parameter* param_; // Could use forward declaration
Buffer buffer_; // Needs full include (value member)
};
Good (Minimal Dependencies)¶
// my_processor.hpp
#include "buffer.hpp" // Only what's needed
namespace audiolab {
class EventDispatcher; // Forward declaration
class Parameter; // Forward declaration
}
class MyProcessor {
EventDispatcher* dispatcher_; // Forward declared
Parameter* param_; // Forward declared
Buffer buffer_; // Fully included
};
// my_processor.cpp
#include "my_processor.hpp"
#include "event_dispatcher.hpp" // Now include for implementation
#include "parameter.hpp" // Now include for implementation
// Can use full API here
Benefits¶
- Faster Compilation: Less to parse in header
- Reduced Coupling: Changes to forward-declared class don't trigger recompile
- Circular Dependencies: Can break circular dependencies
Limitations¶
Can't: - Create instances (value members) - Call methods - Access data members - Use sizeof() - Inherit from
Can: - Declare pointers/references - Declare function parameters/returns - Use in typedef/using
Rule of Thumb: If you only mention the type's name (not use it), forward declare.