## 2 The Framework
### Design Fundamentals  
The conditions in which the framework is supposed to work constrain significantly the scope of what is possible. In particular,  
1. The main Csound engine is written in C. As we have noted, it instantiates opcodes and makes calls to opcode processing functions, but it does not support any C++ facilities. 2. Polymorphism [20] via virtual functions [21] is not possible (due to 1) since C does not provide dynamic dispatch. All function calls have to be resolved at compile time. 3. The process of registering an opcode with the engine requires that processing functions are defined as static. As we have seen, up to three different functions should be registered (for different action times). 4. In C, the sub-classing of the base structure (OPDS) is achieved by adding this as its first member variable. In relation to the last item above, we will assume a similar behaviour in C++. While defining an opcode base class for the framework, we have the practical expectation that all C++ compilers place subclass members contiguously to their superclass object in memory. Although this layout is not imposed by the C++ standard, it is the standard practice [22]. CPOF assumes then that the following code  
struct OPCD {  OPDS h; }; is binary equivalent to  
struct OPCD : OPDS { };  
The absence of a virtual function mechanism for overriding base class methods can be overcome with different compile time strategies. One of the possibilities for designing a framework based on polymorphism without the use of dynamic binding is to employ a method called _curiously recurring template pattern_ (CRTP) [23]. However, we can do better with a much simpler approach. Given the constraints in which the opcode classes are meant to operate, there is no need for a compile-time mimicking of the virtual-function mechanism. This is because it is not our objective to have a general purpose framework for C++ programs, where users would be instantiating their own objects and possibly using generic pointers and references that need to bind to the correct override. Here the scope is much narrower: the developer supplies the code, but will not call it directly (the functions are effectively callbacks). Csound does the instantiation and the calls, so we can make the decision at compile time just by providing functions that _hide_ rather than _override_ (in the dynamic binding sense) the base class ones. In this case, hiding plays the same role as overriding, there is in practice no distinction between the two. A plugin base class can be defined from which we will inherit to create the actual opcodes. This class will inherit from OPDS (which is opaque to CPOF) and provide some extra members that are commonly used by all opcodes. It will also provide stub methods for the processing functions, which then can be _specialised_ (hidden, in reality) by derived class methods. An initial design for an opcode base class would thus be  
struct Plugin : OPDS {  // dataspace ...  // stub methods  int init() { return OK; }  int kperf() { return OK; }  int aperf() { return OK; } }; from which we would inherit our own class to implement the new opcode:  
struct MyClass: Plugin { ...  }; Given that in any practical applications they will not ever be called, it would seem that these stubs are surplus to requirements. However, having these allows a considerable simplification in the plugin registration process. We can just register any plugin in the same way, even if it does only provide one or two of the required processing functions. The stubs play an important role to keep the compiler happy in this scheme, even if Csound will not take any notice of them. This mechanism requires that we provide function templates for opcode registration. These get instantiated with exactly the derived types and are used to glue the C++ code into Csound.