KAHIBARO
Discord Login Register

3.4. Header and Source Files

`.hh` files

In a Geant4 application you will see many files ending in .hh. These are C++ header files. A header file describes the interface of your classes and functions. It tells the compiler what exists, without providing all the implementation details.

In a typical Geant4 class, the header file contains the class declaration. This includes the class name, its base class, its member variables, and the declarations of its member functions. Constructors, destructors, and important methods such as Construct() for detector geometry or BeginOfRunAction() for a run action are all declared here.

For example, a simple header for a detector construction class might look like:

cpp
#ifndef MyDetectorConstruction_hh
#define MyDetectorConstruction_hh
#include "G4VUserDetectorConstruction.hh"
#include "globals.hh"
class G4VPhysicalVolume;
class MyDetectorConstruction : public G4VUserDetectorConstruction
{
  public:
    MyDetectorConstruction();
    virtual ~MyDetectorConstruction();
    virtual G4VPhysicalVolume* Construct();
  private:
    // Member variables go here
};
#endif

The header uses only what is needed to describe the class. Implementations of methods are not written here, except sometimes short one line functions that you may mark inline. In Geant4 examples, you will often see inline getters or simple utility methods defined directly in the .hh file for performance and simplicity, but all nontrivial code usually goes to the .cc file.

For a beginner, it is useful to think of .hh files as the place that other parts of the program read in order to know how to use your class. Your main() function and other user classes will include these headers with #include "MyDetectorConstruction.hh" and then create objects or call methods that are declared there.

Because Geant4 is a large object oriented framework, you will create many header files: one for your detector construction, one for your primary generator, one for your physics list or physics configuration, and one for each user action class. Keeping the interface of each class in a separate .hh file helps keep your code organized and makes it easier to reuse classes across different applications.

You should avoid putting executable code or global variables in header files. If you put real code (for example, full function bodies) in a header and include that header from several .cc files, you can easily create multiple definition problems during linking. Instead, keep your logic in .cc files and use headers only for declarations and very short inline definitions that you intentionally want to share.

`.cc` files

Files ending in .cc are the C++ source files that hold the implementations of the classes and functions declared in your headers. In Geant4 examples, .cc is used instead of .cpp, but they mean the same thing for the compiler.

At the top of a .cc file, you include the corresponding header file, then write the method definitions. For the detector construction example above, the source file could look like:

cpp
#include "MyDetectorConstruction.hh"
#include "G4Box.hh"
#include "G4LogicalVolume.hh"
#include "G4PVPlacement.hh"
#include "G4NistManager.hh"
#include "G4SystemOfUnits.hh"
MyDetectorConstruction::MyDetectorConstruction()
: G4VUserDetectorConstruction()
{
}
MyDetectorConstruction::~MyDetectorConstruction()
{
}
G4VPhysicalVolume* MyDetectorConstruction::Construct()
{
  G4NistManager* nist = G4NistManager::Instance();
  G4Material* worldMat = nist->FindOrBuildMaterial("G4_AIR");
  G4double worldSize = 1.0*m;
  G4Box* solidWorld =
    new G4Box("World", 0.5*worldSize, 0.5*worldSize, 0.5*worldSize);
  G4LogicalVolume* logicWorld =
    new G4LogicalVolume(solidWorld, worldMat, "World");
  G4VPhysicalVolume* physWorld =
    new G4PVPlacement(0,
                      G4ThreeVector(),
                      logicWorld,
                      "World",
                      0,
                      false,
                      0,
                      true);
  return physWorld;
}

In this file, you write the actual algorithms and logic: building geometry, configuring materials, defining actions, filling histograms, and so on. The compiler uses the header to check that your definitions match the declarations, and then compiles the source file into an object file that is later linked into the executable.

A few practical points are important for Geant4 work. First, always include the corresponding header as the first include in the .cc file. This helps ensure your header is self-contained and has all includes it needs. Second, keep one main class per pair of .hh and .cc files, especially in a teaching or small project context. For example, PrimaryGeneratorAction.hh and PrimaryGeneratorAction.cc should only define and implement PrimaryGeneratorAction. This makes it easier to map code files to the Geant4 user initialization hooks and to the CMake build.

Your main() function is also normally placed in a .cc file, often called example.cc, main.cc, or something similar. That file will include the user headers such as DetectorConstruction.hh and ActionInitialization.hh, create the run manager, register your classes, and start the simulation. Because main() must see the full class declarations, it includes the .hh files, not the .cc files.

In CMake configuration, only .cc files are added to the executable or library sources. Header files are discovered automatically through #include. Understanding this separation between interface in .hh and implementation in .cc is essential for building and extending Geant4 applications.

Include guards

Header files are often included from several different source files, and sometimes headers include other headers. This can easily lead to the same header being processed multiple times by the compiler. If the compiler sees the same class definition more than once in one translation unit, it will report an error about redefinition.

Include guards solve this problem. An include guard is a simple preprocessor pattern that makes sure the contents of a header file are only included once per compilation unit. You saw an example already:

cpp
#ifndef MyDetectorConstruction_hh
#define MyDetectorConstruction_hh
// header contents
#endif

The idea is that MyDetectorConstruction_hh is a unique macro name. During the first inclusion, it is not defined, so the preprocessor defines it and includes all the header contents. If another file includes the header again, the macro is already defined, so the whole block is skipped.

Always protect every header file with a unique include guard macro, or use #pragma once if and only if your compiler and project policy allow it. Missing include guards in Geant4 headers will almost always lead to compile time errors due to multiple class definitions.

Choosing a good macro name is important. It must be unique across the whole project. A common convention is to base it on the file path and convert it to uppercase, for example MYPROJECT_DETECTORCONSTRUCTION_HH. In Geant4 examples, you will see names like B1DetectorConstruction_hh or similar, where the example name appears in the macro.

Some compilers support the shorter directive

cpp
#pragma once

at the top of a header file. This has the same purpose as an include guard, but it is not part of the C++ standard, even though it is widely supported. For maximum portability and for consistency with Geant4 coding style, traditional include guards are a safe default, especially in educational projects.

From a practical point of view in Geant4, include guards make it safe to have complex include chains. For example, ActionInitialization.hh might include RunAction.hh, which itself includes AnalysisManager.hh. Your main.cc can include both ActionInitialization.hh and RunAction.hh directly without worrying about duplicate definitions, as long as each header has proper guards.

Whenever you create a new user class header, make setting up the include guard the first step. Many code editors and IDEs can insert the pattern automatically. Doing this consistently avoids subtle and confusing compilation problems later in your Geant4 development.

Views: 12

Comments

Please login to add a comment.

Don't have an account? Register now!