Added garfield and snoopy classes to ./example which are derived from the cat and dog classes.
This commit is contained in:
parent
6ca258f882
commit
32e7d0b337
13 changed files with 1519 additions and 69 deletions
111
example/snoopy.h
Normal file
111
example/snoopy.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* This file is part of libooc.
|
||||
* https://xw3.org/hanez/libooc
|
||||
*
|
||||
* Copyright 2026 Johannes Findeisen <you@hanez.org>
|
||||
* Licensed under the terms of the Apache-2.0 license.
|
||||
* https://opensource.org/license/apache-2-0
|
||||
*/
|
||||
|
||||
#ifndef SNOOPY_H
|
||||
#define SNOOPY_H
|
||||
|
||||
#include "dog.h"
|
||||
|
||||
typedef struct Snoopy Snoopy;
|
||||
|
||||
/*
|
||||
* A subclass of Dog, and so a subclass of a subclass on the other branch of the
|
||||
* example hierarchy.
|
||||
*
|
||||
* The embedded Dog comes first, which is the same arrangement Garfield uses: the
|
||||
* ooc_object header stays at offset zero where the library looks for it, and the
|
||||
* upcast to Animal * is a no-op cast because every address is the same. No member
|
||||
* may go before the base.
|
||||
*
|
||||
* Snoopy adds an imagination and keeps the flying hours to itself. The important
|
||||
* thing about this branch is not the members but the shape: the hierarchy now
|
||||
* forks, so Garfield is a Cat and Snoopy is a Dog and neither is anything to do
|
||||
* with the other beyond their shared Animal. Field lookup walks up and stops at
|
||||
* the first class that has the name, so "imagination" never resolves on a
|
||||
* Garfield and "colour" never resolves on a Snoopy.
|
||||
*/
|
||||
struct Snoopy {
|
||||
Dog dog;
|
||||
|
||||
/*
|
||||
* Snoopy's own field, and the only public one it adds. Marked as owned in
|
||||
* the field table, so ooc_set() releases the string it displaces exactly as
|
||||
* it does for a Dog's breed. Nothing about ownership changes with depth.
|
||||
*/
|
||||
char *imagination;
|
||||
|
||||
/*
|
||||
* A private counter, set once and not adjustable from outside.
|
||||
*
|
||||
* Two underscores rather than one, which is a difference in degree rather
|
||||
* than in kind: `__flights` is unreadable as well as unwritable by name, so
|
||||
* snoopy_flights() is the only way to learn it. Dog has no private field of
|
||||
* its own and Animal hides `__legs` the same way, so the convention is
|
||||
* visible at every level of this hierarchy.
|
||||
*/
|
||||
int __flights;
|
||||
};
|
||||
|
||||
/*
|
||||
* Snoopy's runtime type record, the value ooc_new() takes.
|
||||
*
|
||||
* Its `super` is Dog_class, so lookup continues from there for "breed" and
|
||||
* onwards to Animal_class for "name", "age", "_id" and "__legs". Its `size` is
|
||||
* sizeof(Snoopy), which has to hold Dog and Snoopy's own members on top.
|
||||
*/
|
||||
extern const ooc_class Snoopy_class;
|
||||
|
||||
/*
|
||||
* Create a Snoopy named `name`, of the given `breed` and `imagination`, 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 Snoopy and answers to Snoopy's `speak` however it is later
|
||||
* reached -- through a Snoopy *, a Dog * or an Animal * alike.
|
||||
*/
|
||||
Snoopy *snoopy_new(const char *name, int age, const char *breed,
|
||||
const char *imagination);
|
||||
|
||||
/*
|
||||
* Initialise the members Snoopy owns, so a subclass of Snoopy could build this
|
||||
* part for itself.
|
||||
*
|
||||
* The third link in the chain of constructors: snoopy_init() composes
|
||||
* dog_init(), which composes animal_init(). Each one installs its own vtable and
|
||||
* the one above overwrites it, so the object ends up speaking as the most
|
||||
* derived class.
|
||||
*
|
||||
* 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 object, an already initialised one, or a failed
|
||||
* copy. Requires zero-initialised members and external synchronization between
|
||||
* constructors in different threads.
|
||||
*/
|
||||
int snoopy_init(Snoopy *snoopy, const char *name, int age, const char *breed,
|
||||
const char *imagination);
|
||||
|
||||
/*
|
||||
* Read back `__flights`, the field ooc_get() withholds.
|
||||
*
|
||||
* The only route to the value, which is what a two-underscore name asks for: no
|
||||
* amount of ooc_get() or ooc_set() will reach it, so a caller wanting the count
|
||||
* has to come through here. Animal exposes `__legs` the same way.
|
||||
*
|
||||
* Returns 0 for a NULL object, which is indistinguishable from a real count of
|
||||
* zero, so a caller that has to tell the two apart should check the pointer
|
||||
* first. The count starts at 0, since Snoopy has not flown anywhere yet.
|
||||
*/
|
||||
int snoopy_flights(const Snoopy *snoopy);
|
||||
|
||||
#endif /* SNOOPY_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue