| References | Casting | Arrays | Import | instanceof | Package | Synchronization | Throwable | finally | Dangerous | Stack | String |
In Java and ACDK, you usually only handle objects via references.
First a little example, in Java and in C++ using acdk.
// Java
boolean
isHello(String str)
{
String hello = new String("Hello");
return str.equalTo(hello);
}
// C++ / acdk
bool
isHello(RString str)
{
RString hello = new String("Hello");
return str->equalTo(hello);
}
|
Beside the difference between boolean and bool, the most significant difference
is member access via '->' and the 'RString' identifier, which is used instead
of String.
In Java, all instances of types derived from Object are handled as a Reference.
You can prove this with the following code:
// java
void foo(StringBuffer sb, boolean getNewBuffer)
{
if (getNewBuffer == false)
sb.append(" Kommer");
else
sb = new StringBuffer("artefaktur");
}
StringBuffer sb = new StringBuffer("Roger");
foo(sb, false); // Callee change contents of sb
System.out.println(sb);
foo(sb, false); // Callee change the reference
System.out.println(sb);
|
To achieve the same, ACDK uses a template, which wraps the underlying object.
The following statement is often found in the header of ACDK:
In general, all references to classes should follow the convention R[Classname].
// Java
void foo()
{
String string = new String("Hallo");
Object object = string; // OK
string = (String)object; // OK, because, RObject contains a String
object = new Object();
try {
string = (Object)object; // This will throw
} catch (RBadCastException ex) {
System.out.println("Oops, you cannot asign an Object to a String");
}
}
|
The same in C++ using acdk:
// C++ / acdk
void foo()
{
RString string = new String("Hallo");
RObject object = string; // OK
string = (RString)object; // OK, because, RObject contains a String
object = new Object();
try {
string = (RString)object; // This will throw
} catch (RBadCastException& ex) {
System::out->println("Oops, you cannot asign an Object to a String");
}
}
|
In Java, you can test if a reference to an object is valid in the following way:
// Java
bool isValid(Object o)
{
if (o == null)
return false;
else
return true;
}
|
Some system headers or other vendor libraries tend to define 'null' with a macro like this:
#define null 0
To avoid problems with name conflicts, the 'null' value in acdk is Nil .
// C++ / acdk
bool isValid(RObject o)
{
if (o == Nil)
return false;
else
return true;
}
|
To explicitely release a reference, you can do following:
// Java
Object o = new Object;
o = null; // release Object;
// C++ / acdk
RObject o = new Object;
o = Nil; // release Object;
|
The ACDK Objects RObject, RStringBuffer and so on, controls
the lifetime of the objects. They count the number of
references holding the underlying object. Therefore
they call the methods:
// increment number of reference hold this object instance
Object::addRef();
// decrement number of reference hold this object instance
Object::releaseRef();
|
If no reference hold the object instance, the object can be
freed.
In normal situation these methods should and must not be used
directly.
See also: Memory.
Smart ACDK references support following basic operations:
- operator ->: access holded Object. If Object is 0, NullPointerException will be
thrown.
Sample:
RStringBuffer sb = new StringBuffer("asdf");
sb->append("asdf"); // accessing method with operator ->
RObject o = Nil;
o->hashCode(); // throws NullPointerException
|
- operator * : dereferencing Object. If Object is 0, NullPointerException will be
thrown.
Sample:
RStringBuffer sb = new StringBuffer("asdf");
StringBuffer& sb2 = *sb;
sb.append("asdf");
|
- operator & : referencing Object.
Sample:
RStringBuffer sb = new StringBuffer("asdf");
StringBuffer* sb2 = &sb;
sb->append("asdf");
|
The & operator will often also used as cast-operator to cast up
in the class hierarchi:
void foo(RWriter out)
{
}
RBinaryWriter bout = getBinaryWriter();
//foo(bout); will not compile, because cannot convert RBinaryWriter to RWriter
foo(&bout); //will compile, because can convert BinaryWriter* to RWriter
|
- _ref_this(): get the pointer to RObject.
because you cannot use the & to get the address of an RObject,
the method _ref_this() is provided.
Sample:
RBinaryWriter bout = getBinaryWriter();
RBinaryWriter* boutptr = bout._ref_this();
|
You should really need this only in very special situations.
RObject is a typedef to RefHolder<Object>.
Different to many other smart pointers using reference counting
this implementation has following advantages:
- The reference counting is thread-safe. You can
use references to the same object in different threads
without any problem. The synchronization is done with
the best performance the platform provides (for example
spinlocks).
- If an Object is allocated on stack, reference counting
is not synchronized. It doesn't make any sence (or is even
imposible to share a stack object reference within thread.
- A pointer or value can be converted to smart reference and vice
versa without any problem.
- There is no explicit ownership of an referenced object.
- Explicit casts are possible. See Casting.
- Unfortunatelly some C++ compiler has problems with
templates, so downcasts has to be done with the &operator.
See Casting.
- Side-casts are possible (A implements interface B and C
You have a reference to B and want to cast it to C.)
- There are reference template for normal classes - ACDK_DECL_CLASS(AClass),
for interfaces - ACDK_DECL_INTERFACE(AInterface) and for exceptions -
ACDK_DECL_THROWABLE(AThrowable) and arrays.
-
Foreign C++ classes - which are not derived from acdk::lang::Object cannot used via an ACDK reference by default.
But you can use the class ExtObjectVal and ExtObjectPtr to wrapp an existing C++ class or struct with a ACDK-Object.
// a foreign struct
struct MyStruct
{
int _ivar;
MyStruct(int i) : _ivar(i) {}
int getI() { return _ivar; }
};
// this macro declares an MyStructObject and RMyStructObject and corresponding array types
// which can be used as normal ACDK Object
ACDK_DECL_EXT_CLASS_VAL(MyStruct);
// ACDK relies on basis services, which is provided by
// acdk::lang::Object
// To implement these service (like hashCode, toString, compareTo, equals)
// implement global functions:
int acdk_hashCode(INP(RMyStructObject) s) { return s->_ivar; }
::acdk::lang::RString acdk_toString(INP(RMyStructObject) s)
{ return acdk::lang::String::valueOf(s->_ivar); }
// now you can use MyStruct in ACDK way:
RMyStructObject iobj = new MyStructObject(42);
int i = iobj->getI();
testAssert(i == 42);
RString s = iobj->toString(); // calls acdk_toString(INP(RMyStructObject) s)
testAssert(s->equals("42") == true);
// Use arrays
RMyStructObjectArray sa= new MyStructObjectArray(1);
sa[0] = new MyStructObject(41);
testAssert(sa->length() == 1);
RMyStructObject t = new MyStructObject(42);
sa->append(t);
testAssert(sa[0]->getI() == 41);
testAssert(sa[1]->getI() == 42);
|
Please refer to API Overview for Smartpointers.
|