/* * This file is part of libooc. * https://xw3.org/hanez/libooc * * Copyright 2026 Johannes Findeisen * Licensed under the terms of the Apache-2.0 license. * https://opensource.org/license/apache-2-0 */ #ifndef DOG_H #define DOG_H #include "animal.h" typedef struct Dog Dog; /* * Derived class. * * The embedded Animal comes first, so a Dog pointer can be handed to any * function expecting an Animal, and Dog adds a breed of its own. * * Two things follow from that ordering. The ooc_object header inside Animal * stays at offset zero, where the library looks for it, and the upcast is a * no-op cast because both addresses are the same -- which is what lets speak() * in dog.c cast its Animal * back to a Dog * without arithmetic. The cost is * that a Dog may not add a member of its own before the base. * * The struct holds no destructor of its own; the one Dog registers lives in * Dog_class and releases both the breed and Animal's name. */ struct Dog { Animal animal; char *breed; }; /* * Dog's runtime type record, the value ooc_new() takes. * * Its `super` is Animal_class, so a Dog inherits Animal's fields, and its * `size` is sizeof(Dog), so the allocation has room for the breed. */ extern const ooc_class Dog_class; /* * Create a Dog named `name` of the given `breed` and return it, or NULL. * * The result has a reference count of one, so ownership is the caller's and it * must reach ooc_release() eventually. Returns NULL if any step of the * construction fails, leaving nothing to release. * * The object is a Dog and answers to Dog's `speak`, whether it is later reached * through a Dog * or an Animal *. */ Dog *dog_new(const char *name, int age, const char *breed); /* * Initialise the members Dog owns, so a subclass constructor can build the Dog * part of a larger object instead of duplicating it. * * This is the second link in the chain of constructors below Animal: a subclass * of Dog calls this, gets Dog's vtable installed, and then overwrites the * vtable with its own the same way dog_new() does. * * The caller supplies storage that ooc_new() has already allocated and * zeroed. On failure the object is left exactly as it was found, so the caller * may release it without a destructor having anything to do. * * Returns 0, or -1 for a NULL dog, an already initialised one, or a failed copy * of the breed. Requires zero-initialised members and external synchronization * between constructors in different threads. */ int dog_init(Dog *dog, const char *name, int age, const char *breed); #endif /* DOG_H */