Objects
Summary
An object is a concrete instance of a class — the actual house built from the blueprint, with its own fields holding its own values, distinct from every other object built from the same class. Where a class describes what shape something has, an object is one, occupying real memory, existing at a specific point during the program's run, and eventually being destroyed or garbage-collected.
Mental Model
If Classes established the blueprint/house analogy, an object is one particular house: it has its own address (its identity — where it lives in memory), its own furniture (its own field values), and changing this house's kitchen doesn't affect any other house built from the same plan. Two objects created from the identical class are like two houses from the identical blueprint on different lots — structurally identical in what fields and methods they have, but independent in what values those fields currently hold.
Instantiation is the act of building the house: calling new Enemy(100)
runs the constructor, allocates memory for a fresh object, and hands back
a reference to it — the object now exists and can be used.
Core Explanation
- Identity vs. equality. Two objects can hold identical field values
(
enemyA.health == enemyB.health) while still being two distinct objects — comparing them with==(for reference types) checks whether two variables refer to the same object, not whether their contents happen to match. This is the direct consequence of reference-type semantics introduced in Data Types. - State. An object's state is the current set of values held in its
fields at any given moment — it changes over the object's lifetime as
methods run (
TakeDamage()changesCurrentHealth), while the object's identity (which specific object it is) stays the same throughout. - Lifetime. An object begins existing when it is instantiated and
stops existing once nothing references it any longer (garbage collected,
in C#) or once it is explicitly destroyed (C++, or Unreal's actor
lifecycle). Code holding a reference to an object that has already been
destroyed is a common source of crashes — the reference is not
automatically invalidated everywhere just because the underlying object
is gone (this is exactly the "null reference" hazard
enemy != nullchecks, introduced in Operators, exist to guard against). this/self. Inside a method,this(C#/C++) refers to the particular object the method was called on — it's how a method knows which object's fields to read and modify without those fields being passed explicitly as parameters every time.- Object graphs. Objects reference other objects (a
Weaponobject might hold a reference to its owningCharacterobject, and vice versa) — a running program's objects, and the references between them, form a graph, not an isolated list. Garbage collection (in managed languages) works by tracing which objects are still reachable from that graph's roots.
Syntax / Examples
C# (Unity)
// Two distinct objects from the same class
Enemy goblin = new Enemy(50);
Enemy troll = new Enemy(300);
goblin.TakeDamage(10); // only affects goblin's state
Debug.Log(goblin.CurrentHealth); // 40
Debug.Log(troll.CurrentHealth); // still 300 — a different object
// Identity vs. equality
Enemy anotherReferenceToGoblin = goblin;
bool sameObject = ReferenceEquals(goblin, anotherReferenceToGoblin); // true
bool sameObjectAsTroll = ReferenceEquals(goblin, troll); // false
C++ (Unreal)
AEnemy* Goblin = GetWorld()->SpawnActor<AEnemy>(GoblinClass, SpawnLocation);
AEnemy* Troll = GetWorld()->SpawnActor<AEnemy>(TrollClass, OtherLocation);
Goblin->TakeDamage(10); // only Goblin's state changes
bool bSameActor = (Goblin == Troll); // false — distinct objects
Unreal Blueprint
Spawn Actor from Class instantiates an object at runtime, returning a
reference pin to the newly created instance — each call produces a
distinct object, exactly like new Enemy(...) in code. Comparing two
object references with an == node checks identity (same underlying
actor), not whether their exposed variables currently match.
Practical Example
A wave of enemies is a list of independent objects, each with its own state, all built from the same class:
List<Enemy> wave = new List<Enemy>();
for (int i = 0; i < waveSize; i++)
{
wave.Add(new Enemy(baseHealth));
}
// Damaging one object never affects the others' state.
wave[0].TakeDamage(999);
bool onlyFirstDied = wave[0].CurrentHealth == 0 && wave[1].CurrentHealth == baseHealth;
Every Enemy in wave shares the same class (same fields, same methods)
but has entirely independent state — this is exactly what makes "spawn 10
enemies from one class" both possible and safe: no object's state can leak
into another's just by existing.
Common Mistakes
- Confusing identity with equality, especially when overriding
Equals()— two objects can be "equal" by value while still being two separate objects in memory; code that needs "is this the same instance" should compare identity, not overridden value-equality. - Holding a reference to a destroyed object — calling a method on an
actor that has already been destroyed in Unreal, or an object a C#
Destroy()call has torn down, is a runtime error; validity should be checked (IsValid, a null check) before use, not assumed. - Believing all objects of a class share state — a mistake usually
rooted in accidentally using a
staticfield (see Classes) where an instance field was intended. - Losing the only reference to an object accidentally, then being surprised the object is unreachable or garbage collected — an object's lifetime is tied to whether anything still references it, not to whether the programmer remembers it exists.
Best Practices
- Use identity comparison (
ReferenceEquals, raw pointer==) when the question is genuinely "is this the same instance," and value/overridden equality only when the question is "do these represent the same value." - Check an object reference's validity before using it whenever its lifetime isn't guaranteed to outlive the code using it.
- Keep object construction (see Classes' constructors) responsible for leaving every new object in a valid, usable state immediately.
- Avoid keeping long-lived references to objects whose lifetime you don't control — prefer re-fetching or re-validating a reference over assuming it's still good far from where it was obtained.
Exercises
- Create two objects from the same class with identical field values, then demonstrate that an identity comparison (not an equality override) reports them as different objects.
- Write a small scenario where a reference to a destroyed object is used without a validity check, then fix it with the appropriate guard.
- Explain, using the wave-of-enemies example, why damaging one
Enemyobject never affects another, even though both came from the same class. - Identify a
staticfield bug (an instance field that was mistakenly madestatic) and describe the symptom it would cause across multiple objects.
Related Concepts
- Classes — the blueprint every object is instantiated from.
- Inheritance — how one class's blueprint can extend another's, changing what objects built from it look like.
References
KNOWLEDGE_SCHEMA.md— GDKB's concept maturity ladder and cross-linking rules.- C# Language Reference — Object-oriented programming: https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/tutorials/oop
- Unreal Engine — Actor Lifecycle: https://dev.epicgames.com/documentation/en-us/unreal-engine/actor-lifecycle-in-unreal-engine