facf0c92e0
Red Bear OS is a full fork. All sources must be available from git clone with zero network access. Removed gitignore rules that excluded fetched source trees under recipes/*/source/, local/recipes/kde/*/source/, local/recipes/qt/*/source/, and vendor source trees. Build artifacts (target/, build/, source.tar, *.o, *.so) remain excluded. 127291 files added — kernel, relibc, base, bootloader, pkgar, all KDE/Qt frameworks, mesa, wayland, DRM drivers, and every other recipe source.
249 lines
11 KiB
C++
249 lines
11 KiB
C++
/* Minimal object-oriented facilities for C.
|
|
Copyright (C) 2006 Free Software Foundation, Inc.
|
|
Written by Bruno Haible <bruno@clisp.org>, 2006.
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
/* This file defines minimal facilities for object-oriented programming
|
|
style in ANSI C.
|
|
|
|
The facilities allow to define classes with single inheritance and
|
|
"virtual" methods.
|
|
|
|
Strict type checking is provided in combination with a C++ compiler:
|
|
The code compiles in ANSI C with less strict type checking; when
|
|
compiled with a C++ compiler, strict type checking is done.
|
|
|
|
In contrast to [OOC] and [OOPC], this implementation concentrates on the
|
|
bare essentials of an object-oriented programming style. It does not
|
|
provide features that are "sometimes useful", but not essential.
|
|
|
|
Features:
|
|
- Combination of fields and methods into a single object. YES
|
|
- Description of objects of same shape and same behaviour
|
|
by a class. YES
|
|
- Single inheritance. YES
|
|
- Multiple inheritance. NO
|
|
- Operator overloading (compile-time polymorphism). NO
|
|
- Virtual methods (run-time polymorphism). YES
|
|
- Information hiding: private/protected/public. private fields
|
|
- Static fields and methods. NO
|
|
- Constructors, destructors. NO
|
|
- 'new', 'delete'. NO
|
|
- Exception handling. NO
|
|
- Garbage collection. NO
|
|
- Templates / Generic classes with parameters. NO
|
|
- Namespaces. NO
|
|
- Hidden 'this' pointer in methods. NO
|
|
- Declaring or implementing several classes in the same file. NO
|
|
|
|
Rationale for NO:
|
|
- Multiple inheritance is not supported because programming languages
|
|
like Java and C# prove that they are not necessary. Modern design
|
|
patterns use delegation more often than composition; this reduces
|
|
the pressure to use multiple inheritance.
|
|
Multiple inheritance of "interfaces" (classes without fields) might
|
|
be considered, though.
|
|
- Operator overloading is not essential: The programmer can rename
|
|
methods so that they carry unambiguous method names. This also makes
|
|
the code more readable.
|
|
- Virtual methods are supported. Non-virtual methods are not: they
|
|
constitute an assumption about the possible subclasses which is more
|
|
often wrong than right. In other words, non-virtual methods are a
|
|
premature optimization - "the root of all evil", according to
|
|
Donald E. Knuth.
|
|
- Information hiding: 'protected' is not supported because it is always
|
|
inappropriate: it prohibits the use of the delegation design pattern.
|
|
'private' is implemented on fields. There are no 'public' fields,
|
|
since the use of getters/setters allows for overriding in subclasses
|
|
and is more maintainable (ability to set breakpoints). On the other
|
|
hand, all methods are 'public'. 'private` methods are not supported
|
|
because methods with static linkage can be used instead.
|
|
- Static fields and methods are not supported because normal variables
|
|
and functions with static or extern linkage can be used instead.
|
|
- Constructors and destructors are not supported. The programmer can
|
|
define 'init' and 'do_free' methods himself.
|
|
- 'new', 'delete' are not supported because they only provide the
|
|
grouping of two lines of code into a single line of code.
|
|
- Exception handling is not supported because conventions with a return
|
|
code can be used instead.
|
|
- Garbage collection is not supported. Without it the programmer's life
|
|
is harder, but not impossible. The programmer has to think about
|
|
ownership of objects.
|
|
- Templates / Generic classes with parameters are not supported because
|
|
they are mostly used for container classes, and container classes can
|
|
be implemented in a simpler object-oriented way that requires only a
|
|
very limited form of class inheritance.
|
|
- Namespaces are not implemented, because they can be simulated by a
|
|
consistent naming convention.
|
|
- A hidden 'this' pointer in methods is not implemented. It reduces the
|
|
transparency of the code (because what looks like a variable access can
|
|
be an access through 'this') and is simply not needed.
|
|
- Declaring or implementing several classes in the same file is not
|
|
supported, because it is anyway good practice to define each class in
|
|
its own .oo.h / .oo.c file.
|
|
|
|
Syntax:
|
|
|
|
The syntax resembles C++, but deviates from C++ where the C++ syntax is
|
|
just too braindead.
|
|
|
|
A root class is declared in a .oo.h file:
|
|
|
|
struct rootfoo
|
|
{
|
|
methods:
|
|
int method1 (rootfoo_t x, ...); ...
|
|
};
|
|
|
|
and in the corresponding .oo.c file:
|
|
|
|
struct rootfoo
|
|
{
|
|
fields:
|
|
int field1; ...
|
|
};
|
|
|
|
A subclass is declared in a .oo.h file as well:
|
|
|
|
struct subclass : struct rootfoo
|
|
{
|
|
methods:
|
|
int method2 (subclass_t x, ...); ...
|
|
};
|
|
|
|
and in the corresponding .oo.c file:
|
|
|
|
struct subclass : struct rootfoo
|
|
{
|
|
fields:
|
|
int field2; ...
|
|
};
|
|
|
|
This defines:
|
|
- An incomplete type 'struct any_rootfoo_representation' or
|
|
'struct subclass_representation', respectively. It denotes the memory
|
|
occupied by an object of the respective class. The prefix 'any_' is
|
|
present only for a root class.
|
|
- A type 'rootfoo_t' or 'subclass_t' that is equivalent to a pointer
|
|
'struct any_rootfoo_representation *' or
|
|
'struct subclass_representation *', respectively.
|
|
- A type 'struct rootfoo_implementation' or
|
|
'struct subclass_implementation', respectively. It contains a virtual
|
|
function table for the corresponding type.
|
|
- A type 'struct rootfoo_representation_header' or
|
|
'struct subclass_representation_header', respectively, that defines
|
|
the part of the memory representation containing the virtual function
|
|
table pointer.
|
|
- Functions 'rootfoo_method1 (rootfoo_t x, ...);' ...
|
|
'subclass_method1 (subclass_t x, ...);' ...
|
|
'subclass_method2 (subclass_t x, ...);' ...
|
|
that invoke the corresponding methods. They are realized as inline
|
|
functions if possible.
|
|
- A declaration of 'rootfoo_typeinfo' or 'subclass_typeinfo', respectively,
|
|
each being a typeinfo_t instance.
|
|
- A declaration of 'ROOTFOO_SUPERCLASSES' or 'SUBCLASS_SUPERCLASSES',
|
|
respectively, each being an initializer for an array of typeinfo_t.
|
|
- A declaration of 'ROOTFOO_SUPERCLASSES_LENGTH' or
|
|
'SUBCLASS_SUPERCLASSES_LENGTH', respectively, each denoting the length
|
|
of that initializer.
|
|
- A declaration of 'rootfoo_vtable' or 'subclass_vtable', respectively,
|
|
being an instance of 'struct rootfoo_implementation' or
|
|
'struct subclass_implementation', respectively.
|
|
- A header file "rootfoo.priv.h" or "subclass.priv.h" that defines the
|
|
private fields of 'struct rootfoo_representation' or
|
|
'struct subclass_representation', respectively.
|
|
|
|
A class implementation looks like this, in a .oo.c file:
|
|
|
|
struct subclass : struct rootfoo
|
|
{
|
|
fields:
|
|
int field2; ...
|
|
};
|
|
|
|
int subclass::method1 (subclass_t x, ...) { ... } [optional]
|
|
int subclass::method2 (subclass_t x, ...) { ... }
|
|
...
|
|
|
|
At the place of the second "struct subclass" definition, the type
|
|
'struct subclass_representation' is expanded, and the macro 'super' is
|
|
defined, referring to the vtable of the superclass. For root classes,
|
|
'super' is not defined. Also, 'subclass_typeinfo' is defined.
|
|
|
|
Each method subclass::method_i defines the implementation of a method
|
|
for the particular class. Its C name is subclass__method_i (not to be
|
|
confused with subclass_method_i, which is the externally visible function
|
|
that invokes this method).
|
|
|
|
Methods that are not defined implicitly inherited from the superclass.
|
|
|
|
At the end of the file, 'subclass_vtable' is defined, as well as
|
|
'subclass_method1 (subclass_t x, ...);' ...
|
|
'subclass_method2 (subclass_t x, ...);' ...
|
|
if they were not already defined as inline functions in the header file.
|
|
|
|
Object representation in memory:
|
|
- Objects have as their first field, called 'vtable', a pointer to a table
|
|
to data and function pointers that depend only on the class, not on the
|
|
object instance.
|
|
- One of the first fields of the vtable is a pointer to the
|
|
'superclasses'; this is a NULL-terminated array of pointers to
|
|
typeinfo_t objects, starting with the class itself, then its
|
|
superclass etc.
|
|
|
|
|
|
[OOC] Axel-Tobias Schreiner: Object-oriented programming with ANSI-C. 1993.
|
|
|
|
[OOPC] Laurent Deniau: Object Oriented Programming in C. 2001.
|
|
|
|
*/
|
|
|
|
#ifndef _MOO_H
|
|
#define _MOO_H
|
|
|
|
/* Get size_t, abort(). */
|
|
#include <stdlib.h>
|
|
|
|
/* An object of this type is defined for each class. */
|
|
typedef struct
|
|
{
|
|
const char *classname;
|
|
} typeinfo_t;
|
|
|
|
/* IS_INSTANCE (OBJ, ROOTCLASSNAME, CLASSNAME)
|
|
tests whether an object is instance of a given class, given as lower case
|
|
class name. */
|
|
#define IS_INSTANCE(obj,rootclassname,classname) \
|
|
(((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses_length \
|
|
>= classname##_SUPERCLASSES_LENGTH \
|
|
&& ((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses \
|
|
[((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses_length \
|
|
- classname##_SUPERCLASSES_LENGTH] \
|
|
== & classname##_typeinfo)
|
|
/* This instance test consists of two comparisons. One could even optimize
|
|
this to a single comparison, by limiting the inheritance depth to a fixed
|
|
limit, for example, say, depth <= 10. The superclasses list would then
|
|
need to be stored in reverse order, from the root down to the class itself,
|
|
and be filled up with NULLs so that the array has length 10. The instance
|
|
test would look like this:
|
|
#define IS_INSTANCE(obj,rootclassname,classname) \
|
|
(((const struct rootclassname##_representation_header *)(const struct any_##rootclassname##_representation *)(obj))->vtable->superclasses \
|
|
[classname##_SUPERCLASSES_LENGTH - 1] \
|
|
== & classname##_typeinfo)
|
|
but the classname##_superclasses_length would no longer be available as a
|
|
simple sizeof expression. */
|
|
|
|
#endif /* _MOO_H */
|