Description Usage Arguments Value Author(s) See Also Examples
The goal of this function is to define a new C++ class that extends the specified C++ class and which allows implementations of the virtual methods within that class (and ancestors) via R functions. This allows us to override some or all of the methods entirely within R and have those R functions be transparently available to other C++ code. One can create an instance of this new C++ class from within R and specify functions for some of the methods either during the construction or during the life of that object. In this way, the class' methods become dynamic. This mechanism is thus very convenient for exploratory prototypying where we can update methods to handle new situations and fix bugs.
We can only override virtual methods in the C++ class, i.e. those methods that are declared virtual in that class or any of its ancestors.
Specifying an R function to use for a C++ method becomes slightly more troublesome when the method is overloaded, i.e. has multiple versions with different signatures.
This function attempts to deal with various forms of inputs and to do it somewhat efficiently by avoiding recomputing information from the translation unit.
If called with one or more class names and the TU nodes it resolves the class nodes and methods Essentially, if one wants to compute the class nodes ahead of time and resolve all their methods, this information can be reused and no computations duplicated uncessarily. It can work with resolved class definitions or the raw class nodes in the tu or with just the name of the class(es) of interest.
The class names of interest can be given as a character vector and the corresponding R names can be given as the names of this character vector. Any missing names are computed using the default naming scheme.
If one has computed the class nodes and resolved their methods already, then it is simplest to loop over the classes of interest and call this function for each of these. See the example below.
1 2 3 4 5 6 7 8 9 | createDerivedClass(className, tu, types = DefinitionContainer(tu),
classNodes = getClassNodes(tu), methods = NULL,
classDefs = getClassDefs(tu, klasses = classNodes),
virtualOnly = TRUE, inheritanceStyle = "public",
typeMap = list(),
RClassName = paste("R", className, sep = ""),
RNativeBaseClassName = c(native = "RDerivedClass", r = "RDerivedClass"),
signatures = list(), dispatchInfo = data.frame(),
...)
|
className |
a value identifying the class which we want to extend, i.e. the base
class of our soon-to-be-created new, derived class.
This can be the name of the class given as a string or alternatively
a node in the translation unit that identifies the class definition,
e.g. returned from a call to |
tu |
the translation unit nodes obtained via a call to |
types |
a DefinitionContainer object which is a mutable object (an environment) used to collect all the resolved TU nodes, data types, routines, etc. so as to avoid having to repeat the same calculations each time a node is needing to be resolved in a different context. |
classNodes |
a list of the nodes in the translation unit object
( |
methods |
a list of the methods for all of the ancestor classes
of the newly defined classes. If the |
virtualOnly |
a logical value indicating whether to provide overriding methods only for the virtual methods defined in the base class or any of its ancestors. |
typeMap |
an object of S3-style class |
inheritanceStyle |
a string specifying the nature of the inheritance, i.e. one of "public" or "protected" |
RClassName |
the name to use for the new C++ class being defined. |
... |
additional parameters passed onto internal functions (origCreateDerivedClass) |
classDefs |
a list of the resolved class descriptions in the translation unit |
RNativeBaseClassName |
a character string giving the name of the C++ class that is used as the base class for newly derived classes that have methods that can be implemented in R. |
signatures |
a list of the call signatures for the different methods |
dispatchInfo |
a data frame. This is passed to and from the different helper functions and builds up information about the number of possible arguments for different methods. |
An list with several components:
classDefinition |
the C++ code defining and implementing this new class |
rsetClass |
the R code defining the R version of this class. |
rsetMethods |
the C++ routine that can be called from R to set the R functions to be used as methods for this class. |
setMethods |
the C++ routine that actually sets these methods in the C++ instance/object |
rsetMethodsFunction |
the R function that sets the method functions within an instance of the newly created class, i.e. that calls the rsetMethods routine |
rfieldAccessors |
R method for accessing the fields in the base class(es) and ancestor classes |
...
Duncan Temple Lang
getClassNodes
resolveType
DefinitionContainer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | ## Not run:
# the next 5 commands are something that we do generally
# when processing code
tu = parseTU(system.file("examples", "shapes.cc.t00.tu", package = "RGCCTranslationUnit"))
z = createDerivedClass("Ellipse", tu)
# Two classes in one action and amortize the cost of calculating the
# class nodes and resolving methods.
z = createDerivedClass(c("Rectangle", "Ellipse"), tu)
# This version explicitly computes the class nodes and resolves the methods
# presumably for use in other circumstances, e.g. generating the bindings to
# the existing classes and
types = DefinitionContainer(nodes = tu)
classNodes = getClassNodes(tu, "shapes")
methods = lapply(classNodes, function(n) resolveType(getClassMethods(n), tu, types))
zz = lapply(c("Rectangle", "Ellipse"),
function(k) {
def = resolveType(classNodes[[k]], tu, types)
createDerivedClass(def, methods = methods[c(k, def@ancestorClasses)])
})
if(identical(zz, z))
cat("Same results with both approaches\n")
#
names(classNodes)
createDerivedClass(c(RRectangle = "Rectangle", RCircle = "Circle", REllipse = "Ellipse"), tu)
klasses = getClassNodes(tu, "shapes")
methods = lapply(klasses, getClassMethods)
def = DefinitionContainer(nodes = tu)
rect = resolveType(klasses[["Rectangle"]], tu, def)
resolvedMethods = lapply(methods, function(x) lapply(x, resolveType, tu, def))
# This is the command that is specific to creating the code defining
# a derived class.
code = createDerivedClass(rect, methods = resolvedMethods["Rectangle"],
RClassName = "R_Rectangle")
code = createDerivedClass(rect, "R_Rectangle", methods = resolvedMethods["Rectangle"], virtualOnly = FALSE)
#
ellipse = resolveType(klasses[["Ellipse"]], tu, def)
code = createDerivedClass(ellipse, methods = methods, virtualOnly = TRUE)
#"R_Ellipse", resolvedMethods[c("Ellipse", "Circle", "Shape")],
# "Ellipse", getFields(klasses[[c("Ellipse")]]),
# virtualOnly = TRUE)
## End(Not run)
|
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.