Show: Delphi C++
Display Preferences

C++ Keyword Extensions

From RAD Studio
Jump to: navigation, search

Go Up to Language Support for the VCL (C++)


This section describes the keyword extensions implemented in C++Builder to support the VCL.

Contents

__classid

The __classid operator is used by the compiler to generate a pointer to the vtable for the specified classname. This operator is used to obtain the metaclass from a class.

Syntax

__classid (classname)

For example, __classid is used when registering property editors, components, and classes, and with the InheritsFrom method of TObject. The following code illustrates the use of __classid for creating a new component derived from TWinControl:

namespace Ywndctrl
{
  void __fastcall PACKAGE Register() {
    TComponentClass classes[1] = {__classid(MyWndCtrl)};
    RegisterComponents("Additional", classes, 0);
  }
}

__delphirtti

__delphirtti can be used to obtain, at run time, information for a specific Delphi-compatible type. Functionally, the __delphirtti function is equivalent to the TypeInfo function available in Delphi.

Example:

TTypeInfo *ti = __delphirtti(TMyType);

See Also

__closure

The __closure keyword is used to declare a special type of pointer to a member function. In standard C++, the only way to get a pointer to a member function is to use the fully qualified member name, as shown in the following example:

class base {
public:
    void func(int x) {
    };
};
 
typedef void(base::*pBaseMember)(int);
 
int main(int argc, char * argv[])
{
    base baseObject;
    pBaseMember m = &base::func; // Get pointer to member ‘func’.
 
    // Call ‘func’ through the pointer to member.
    (baseObject.*m)(17);
    return 0;
}

However, you cannot assign a pointer to a member of a derived class to a pointer to a member of a base class. This rule (called contravariance) is illustrated in the following example:

class derived : public base {
public:
    void new_func(int i) {
    };
};
 
int main(int argc, char * argv[])
{
    derived derivedObject;
    pBaseMember m = &derived::new_func; // ILLEGAL
 
    return 0;

The __closure keyword extension allows you to skirt this limitation, and more. Using a closure, you can get a pointer to member function for an object (for example, a particular instance of a class). The object can be any object, regardless of its inheritance hierarchy. The object's pointer is automatically used when calling the member function through the closure. The following example shows how to declare and use a closure. The base and derived classes provided earlier are assumed to be defined.

int main(int argc, char * argv[]) {
    derived derivedObject;
    void(__closure * derivedClosure)(int);
 
    // Get a pointer to the ‘new_func’ member.
    // Note the closure is associated with the
    // particular object, ‘derivedObject’.
    derivedClosure = derivedObject.new_func;
 
    derivedClosure(3); // Call ‘new_func’ through the closure.
    return 0;
}

For a code example, see TRegExReplace (C++).

Closures also work with pointers to objects, as illustrated in this example:

void func1(base * pObj)
{
    // A closure taking an int argument and returning void.
    void(__closure * myClosure)(int);
 
    // Initialize the closure .
    myClosure = pObj->func;
 
    // Use the closure to call the member function.
    myClosure(1);
    return;
}
 
int main(int argc, char * argv[])
{
    derived derivedObject;
    void(__closure * derivedClosure)(int);
 
    derivedClosure = derivedObject.new_func; // Same as before...
    derivedClosure(3);
 
    // We can use pointers to initialize a closure, too.
    // We can also get a pointer to the ‘func’ member function
    // in the base class.
    func1(&derivedObject);
    return 0;
}

Notice that we are passing a pointer to an instance of the derived class, and we are using it to get a pointer to a member function in the base class--something standard C++ does not allow us to do.

Closures are a key part of the C++ Builder RAD environment. They give us the ability to assign an event handler in the Object Inspector. For example, a TButton object has an event called OnClick. In the TButton class, the OnClick event is a property that uses the __closure keyword extension in its declaration. The __closure keyword allows us to assign a member function of another class (typically a member function in a TForm object) to the property. When you place a TButton object on a form, and then create a handler for the button’s OnClick event, C++ Builder creates a member function in the button’s TForm parent, and assigns that member function to the OnClick event of TButton. This way, the event handler is associated with that particular instance of TButton, and no other.

__property

The __property keyword declares an attribute of a class. Properties appear to the programmer just like any other attribute (field) of a class. However, like its Object Pascal counterpart, C++ Builder’s __property keyword adds significantly more functionality beyond just examining and changing the value of the attribute. Since property attributes completely control access to the property, there are no restrictions on how you implement the property within the class itself.

Syntax

__property type propertyName [index1Type index1 ][indexNType indexN ] = { attributes }; 

where:

  • type is an intrinsic or previously declared data type.
  • propertyName is any valid identifier.
  • indexNType is an intrinsic or previously declared data type.
  • indexN is the name of an index parameter that is passed to the property’s read and write functions.
  • attributes is a comma-separated sequence of read, write, stored, or index.

The indexN parameters in square brackets are optional. If present, they declare an array property. The index parameters are passed to the read and write methods of the array property.

The following example shows some simple property declarations:

 class  PropertyExample { 
 
 private: 
 
 int  Fx,Fy; 
 
 float  Fcells[100][100]; 
 
 protected : 
 int  readX() {  return (Fx);  } 
 void  writeX( int  newFx) { Fx = newFx;  } 
 
 double  computeZ() { 
 
 // Do some computation and return a floating-point value... 
 
 return (0.0); 
 
 }  float  cellValue( int  row,  int  col) {  return (Fcells[row][col]); } 
 
 public: __property int  X = { read=readX, write=writeX };  __property int  Y = { read=Fy };  __property double  Z = { read=computeZ };  __property float  Cells[int row][int col] = { read=cellValue }; 
 
 };

This example shows several property declarations. Property X has read-write access through the member functions readX and writeX, respectively. Property Y corresponds directly to the member variable Fy, and is read-only. Property Z is a read-only value that is computed; it is not stored as a data member in the class. Finally, the Cells property demonstrates an array property with two indices. The next example shows how you would access these properties in your code:

 PropertyExample myPropertyExample ; 
 myPropertyExample.X = 42; // Evaluates to: myPropertyExample.WriteX(42) ; 
 int  myVal1 = myPropertyExample.Y; // Evaluates to: myVal1 = myPropertyExample.Fy ; 
 double  myVal2 = myPropertyExample.Z; // Evaluates to: myVal2 = myPropertyExample.ComputeZ() ; 
 float  cellVal = myPropertyExample[3][7]; // Evaluates to : 
 
 // cellVal = myPropertyExample.cellValue(3,7);

Properties have many other variations and features not shown in this example.

Properties can also:

  • Associate the same read or write method with more than one property, by using the index attribute.
  • Have default values.
  • Be stored in a form file.
  • Extend a property defined in a base class.

__published

The __published keyword specifies that properties in that section are displayed in the Object Inspector, if the class is on the Component palette. Only classes derived from TObject can have __published sections.

The visibility rules for published members are identical to those of public members. The only difference between published and public members is that Object Pascal-style run-time type information (RTTI) is generated for data members and properties declared in a __published section. RTTI enables an application to dynamically query the data members, member functions, and properties of an otherwise unknown class type.

Note: Properties, Pascal intrinsic or VCL-derived data members, member functions, and closures are allowed in a __published section. Fields defined in a __published section must be of a class type. Properties defined in a __published section cannot be array properties. The type of a property defined in a __published section must be an ordinal type, a real type, a string type, a small set type, a class type, or a method pointer type.

See Also

Personal tools
In other languages