Using C++ with Caché
Dynamic Binding
[Back] [Next]
Go to:

Instead of generating C++ classes, you can use a Dyn_obj, a class that allows you to work with Caché classes dynamically. This can be useful for writing applications or tools that work with classes in general and that do not depend on particular Caché classes. However, this generality comes at the price of the lack of static analysis of the code by a C++ compiler and a slightly slower performance. InterSystems recommends that you work with generated classes if you know what classes you need at the time of writing a program.

Construction of a Dyn_obj Proxy
As any other proxy, Dyn_obj has the following methods for creating a proxy object:
   static d_ref<Dyn_obj> openref(Database* db, 
      int ref, 
      const_name_t type);      // const_name_t is a typedef for const wchar_t*

   static d_ref<Dyn_obj> create_new(Database* db,
      const_name_t type,
      const_str_t init_val = 0,   // const_str_t is a typedef of const wchar_t*
      Db_err* err = 0);

   static d_ref<Dyn_obj> open(Database* db,
      const d_binary& oid,
      int concurrency = -1,
      int timeout = -1,
      Db_err* err = 0);

   static d_ref<Dyn_obj> openid(Database* db,
      const_name_t type,
      const_str_t id,
      int concurrency = -1,
      int timeout = -1,
      Db_err* err = 0);

They differ from the same methods for generated classes only in the additional parameter for the name of the class.
In addition, Dyn_obj has a method, init(), that allows you to construct a Dyn_obj instance from the result of get_property(), run_obj_method(), and run_class_method() methods from Dyn_obj:
static d_ref<Dyn_obj> init(t_istream& in, Database* db);
Construction of Values from Calling Dyn_obj Methods
All values returned from calling Dyn_obj methods are returned inside t_istream (transport input stream). If the value is an instance of a data type, then it can be constructed from t_istream alone, such as:
   d_int val(in);

where in is of type t_istream.
If the value is an object, then t_istream contains its OREF and class name. This means that you will also need a Database object. If you know the type of the returned object at compile time, then you can use the openref() method of that type. For example, if the returned object is of type Sample.Person, then the object can be constructed as
   d_ref<Sample_Person> p = Sample_Person::openref(db, d_int(in));

d_int(in) creates a temporary d_int value that contains the OREF, and the d_int value is converted to an int. Otherwise, it can be constructed as
   d_ref<Dyn_obj> p = Dyn_obj::openref(in, db);

and the type of the object will be read from the input stream. The signature of the init() method matches constructors from other D_type instances, except that the Database pointer is not 0.
Properties and Methods
Once you construct a Dyn_obj proxy, you can use it to get or set property values, run queries, and run and methods:
   t_istream& get_property(const_name_t prop_name);
   void set_property(const_name_t prop_name, D_type* val);
   void get_query(const_name_t query_name, d_query& query) const;
   // const_name_t is a typedef for const wchar_t*
In order to run a method, you should pass an array of pointers to arguments (D_type*) and the number of arguments. You can use the buffer allocated by a Database object, such as:
   D_type* args[2]; 
   args[0] = &arg1;
   args[1] = &arg2;
   // code

it can store max_num_obj_args pointers (the maximum allowed number of arguments). The signature of run_obj_method() is:
   t_istream& run_obj_method(
      const_name_t mtd_name,   // const_name_t is a typedef for const wchar_t*
      D_type** args,
      int num_args);

To run a class method, you can use run_class_method():
   static t_istream& run_class_method(Database* db,
      const_name_t cl_name,   // const_name_t is a typedef for const wchar_t*
      const_name_t mtd_name,
      D_type** args,
      int num_args);

The values for arguments passed by reference will be changed inside these methods. For example,
   const_name_t cl_name = __NAME_V(Sample.Person);

   D_type* args[2]; 

   d_ref<Dyn_obj> p = Dyn_obj::openid(db, cl_name, __STRING_V(1));
   // create a proxy

   d_string dob(p->get_property(__NAME_V(DOB)));
   // get date of birth

   d_int arg1(2);
   d_int arg2(3);

   args[0] = &arg1;
   args[1] = &arg2;
   d_int res = p->run_obj_method(__NAME_V(Addition), args, 2);

   args[0] = &dob;
   d_int age = 
      Dyn_obj::run_class_method(db, cl_name, __NAME_V(CurrAge), args, 1);

   d_query by_name(db);
   p->get_query(__NAME_V(ByName), by_name);

The pointers in the array of arguments cannot point to temporary variables. Code such as the following may result in a crash:
   args[ii] = &d_int(1); // DO NOT USE!