BPVM Snack Pack #6 - The CDO Mystery: Your Class’s Secret Template | ebp BPVM Snack Pack #6 - The CDO Mystery: Your Class’s Secret Template | ebp BPVM Snack Pack #6 - The CDO Mystery: Your Class's Secret Template | ebp
Post

BPVM Snack Pack #6 - The CDO Mystery: Your Class's Secret Template

Every Blueprint class has a hidden template object that nobody talks about. Meet the CDO - the mysterious instance that defines what 'default' really means.

BPVM Snack Pack #6 - The CDO Mystery: Your Class's Secret Template

The content in this post is based on Unreal Engine 5.6.0

BPVM Snack Pack - Quick Blueprint knowledge drops! Part of the Blueprint to Bytecode series.

The Mystery Object

You’ve created a Blueprint class. You haven’t spawned any instances yet. But surprise - an instance already exists.

It’s called the Class Default Object (CDO), and it’s been quietly living in memory since your class was loaded.

What Is a CDO?

Think of the CDO as the master mold for your class:

1
2
3
4
5
// When you create BP_MyActor...
UClass* MyClass = BP_MyActor::StaticClass();

// This already exists!
AActor* CDO = MyClass->GetDefaultObject();  // The secret instance

The CDO is:

  • A real instance of your class (it’s an actual object in memory!)
  • Created automatically when the class loads
  • Never spawned in the world (it exists in limbo)
  • The template for all future instances

Why Does Every Class Need One?

Problem: When you spawn an actor, where do its default values come from?

Bad Solution: Store defaults as metadata somewhere

1
2
3
4
5
6
// Imaginary bad design
class ClassMetadata {
    float DefaultHealth = 100;
    FString DefaultName = "Player";
    // Hundreds of properties...
};

Unreal’s Solution: Just create one “perfect” instance and copy from it!

1
2
3
4
5
6
7
// The CDO IS the defaults
AActor* CDO = GetDefault<AActor>();
CDO->Health = 100;  // Set once
CDO->Name = "Player";

// Spawning copies from CDO
AActor* NewActor = SpawnActor();  // Copies all properties from CDO

The Magic Moment

When you edit “Default” values in the Blueprint editor:

Blueprint Editor showing default values

You’re not editing metadata. You’re editing the CDO directly!

1
2
3
4
5
// In Blueprint Editor, when you set Health = 100
CDO->Health = 100;  // You're literally setting a property on the CDO

// Later, when spawning
NewInstance->Health = CDO->Health;  // Copy from CDO

CDO in Action

Here’s the lifecycle:

1. Class Creation

1
2
3
4
5
// Blueprint gets compiled
UBlueprintGeneratedClass* NewClass = CompileBlueprint();

// CDO is created immediately
UObject* CDO = NewClass->GetDefaultObject();

2. Setting Defaults

1
2
3
4
// You edit in Blueprint editor
CDO->MaxHealth = 150;
CDO->TeamColor = FColor::Red;
CDO->WeaponClass = AK47::StaticClass();

3. Instance Creation

1
2
3
4
5
6
7
// Player spawns your actor
AActor* Instance = World->SpawnActor<AActor>(BP_MyActor);

// Under the hood:
// 1. Allocate memory
// 2. Copy all properties from CDO
// 3. Run constructor

The Revert Button Mystery

Ever wondered how the “Revert to Default” button works?

![Property with revert button in editor]

It’s just comparing to the CDO:

1
2
3
4
5
6
bool IsModified = (Instance->Health != CDO->Health);
// If true, show yellow revert button

void RevertToDefault() {
    Instance->Health = CDO->Health;  // Just copy from CDO!
}

CDO vs Constructor Defaults

C++ Constructor:

1
2
3
AMyActor::AMyActor() {
    Health = 100;  // Runs EVERY spawn
}

CDO System:

1
2
3
4
5
// Set once on CDO
CDO->Health = 100;

// Spawning just copies memory (faster!)
memcpy(NewInstance, CDO, sizeof(AActor));

The CDO approach is much faster for spawning many instances!

The Hidden CDO Lifecycle

During Compilation:

1
2
3
4
5
6
7
8
9
10
11
12
13
void CompileBlueprint() {
    // Old CDO still has player's configured defaults
    UObject* OldCDO = OldClass->GetDefaultObject();

    // Clean the class
    CleanAndSanitizeClass(OldClass);

    // Recompile everything
    CompileClass(NewClass);

    // Copy defaults from old CDO to new CDO!
    CopyPropertiesFrom(OldCDO, NewCDO);
}

This is why your default values survive recompilation!

CDO Gotchas

1. CDO Exists in Editor AND Runtime

1
2
3
4
5
// In editor
CDO->SomeProperty = 10;  // Editing defaults

// In packaged game
CDO->SomeProperty;  // Still 10! (read-only now)

2. Never Modify CDO at Runtime

1
2
// DON'T DO THIS in gameplay code!
CDO->Health = 200;  // You just changed defaults for ALL future spawns!

3. CDO and Hot Reload

1
2
3
4
// During hot reload
OldCDO->SaveDefaults();
RecompileClass();
NewCDO->RestoreDefaults();  // Your settings survived!

Quick Takeaway

  • Every class has a CDO (Class Default Object) - a hidden template instance
  • When you edit defaults in Blueprint, you’re editing the CDO
  • Spawning actors copies properties from the CDO (fast!)
  • The CDO survives recompilation (that’s why defaults persist)
  • Never modify the CDO at runtime (it affects all future spawns)

The CDO Is Everywhere

Next time you:

  • Set a default value in Blueprint
  • Hit the revert button
  • Spawn an actor
  • Recompile a Blueprint

Remember: You’re interacting with the CDO, the secret template object that makes Unreal’s class system work!

Want More Details?

For the complete explanation with code:

Next up: How node handlers turn your graph into code!


🍿 BPVM Snack Pack Series

This post is licensed under CC BY 4.0 by the author.