본문 바로가기

Software/C/C++

[CBuilder]C++ Builder Keyword extensions

This section describes ANSI-conforming keyword extensions implemented in C++Builder to support the VCL and CLX.
The __declspec keyword also provides VCL support.

__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 meta class 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);
}
}

__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 (i.e. a particular instance of a class). The object can be any object, regardless of its inheritance hierarchy. The object's this 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);
derivedClosure = derivedObject.new_func; // Get a pointer to the 'new_func' member.
// Note the closure is associated with the
// particular object, 'derivedObject'.
derivedClosure(3); // Call 'new_func' through the closure.
return 0;
}

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.

For more information about events and closures, see Creating events

__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 will be passed to the property's read and write functions.
attributes is a comma separated sequence of read, write, stored, default (or nodefault), 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; //  Eval uates to: myPropertyExample .Write X(42);
int myVal1 = myPropertyExample.Y; //  Eval uates to: myVal1 = myPropertyExample.Fy;
double myVal2 = myPropertyExample.Z; //  Eval uates to: myVal2 = myPropertyExample.ComputeZ();
float cellVal = myPropertyExample[3][7]; //  Eval uates 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

For more information about properties, see Creating properties

__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 runtime 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: No constructors or destructors are allowed in a __published section. Properties, Pascal intrinsic or VCL or CLX derived data-members, member functions, and closures are allowed in a __publishedsection. Fields defined in a __publishedsection must be of a class type. Properties defined in a __publishedsection cannot be array properties. The type of a property defined in a __publishedsection must be an ordinal type, a real type, a string type, a small set type, a class type, or a method pointer type.