Click here to Skip to main content
15,897,371 members
Articles / Desktop Programming / MFC

Introduction to ACF (Another C++ Framework)

Rate me:
Please Sign up or sign in to vote.
4.86/5 (36 votes)
27 May 200411 min read 136.4K   739   49  
This article introduces ACF, a C++ framework which brings the .NET framework to standard C++.
<html>

<head>
<title>Introduction to ACF</title>
<style> <!-- h1 { font-size: 18pt; font-family:Verdana }
	h2 { font-size: 14pt; font-family:Verdana }
	body { font-family: Verdana; font-size: 10pt }
	p { font-family: Verdana; font-size: 10pt }
	pre { padding:8px; font-family: Lucida Console; font-size: 10pt; background-color:#DDDDDD }
	.inlinecode { font-family: Lucida Console; font-size: 10pt; color:#800000 }
	--></style>
</head>

<body>

<h1>Introduction to ACF (Another C++ Framework)</h1>
<p>The latest version can be found
<a href="http://sourceforage.net/projects/acfproj/">here</a>.</p>
<p>If you&#39;d like to contribute, please e-mail the project admin.</p>
<h2>Abstract</h2>
<p>This document provides an introduction to ACF, a C++ framework designed to implement 
part of the .NET framework in standard C++. Knowledge of C++ and the .NET Framework 
is assumed.</p>
<h2>Contents</h2>
<ul>
	<li>What is ACF</li>
	<li>Why ACF</li>
	<li>Project vision and plan</li>
	<li>Getting started</li>
	<li>Basic type system</li>
	<li>Exceptions</li>
	<li>Arrays and collections</li>
	<li>Delegates and events</li>
	<li>Strings and text</li>
	<li>I/O</li>
	<li>Threading</li>
	<li>History</li>
	<li>Contact</li>
</ul>
<h2>What is ACF</h2>
<p>ACF (Another C++ Framework), is a C++ framework designed to bring the power and 
RAD of the .NET framework to standard C++. ACF does this by implementing the features 
and APIs of the .NET framework in standard C++, and at the same time take advantage 
of C++ unique features such as templates.</p>
<h2>Why ACF</h2>
<p>The .NET framework is definitely the future development platform of Microsoft, 
and C# is the best programming language for that platform. However, today there 
are thousands of existing C++ projects and developers. These projects are not likely 
to be totally rewritten for .NET, and the developers are facing the headache choice 
between the RAD and benefits of C# and the .NET framework and the performance and 
control of C++. Apparently, the C++ community need a bridge now before moving to 
the .NET in the future.</p>
<p>The solution from Microsoft is C++ Managed Extension. C++ ME tries to bring C++ 
to .NET, the result is that C++ code can be compiled to IL, and managed code can 
easily interop with native code. However, C++ ME may not be a good choice for many 
projects and developers. First, C++ is almost the symbol of performance and control, 
but JIT and GC is very slow, and the runtime is also too huge for many applications. 
Second, C++ is already very complex and hard to learn and use, C++ ME adds to it.</p>
<p>ACF tries to solve this problem from another side - bring .NET to C++. By implementing 
the .NET framework in standard C++, ACF helps existing C++ projects and developers: 
1) ACF can be used in existing or new C++ projects (ACF works seamlessly with MFC/ATL/STL, 
etc), and everything compiles to machine code. 2) Developers can use existing C++ 
skills and at the same time use concepts and APIs that are very close to the .NET 
framework. Their new skills are reusable across C#, C++ and C++ ME (for example, 
they always use <span class="inlinecode">String::Format</span> to build formatted 
strings). 3) ACF also helps when porting code between C++ and C#.</p>
<h2>Project vision and plan</h2>
<p>As stated, the vision of ACF project is to deliver a modern C++ framework that 
implements part of the .NET framework. Currently we&#39;ll focus on the portable runtime 
libraries (Corlib, System, XML) and windows client technologies (Drawing, Windows 
Forms, Data). For server-side programming you should choose Java or C#.</p>
<p>The development plan is as follows:</p>
<table border="1" width="100%" id="table1" style="border-collapse: collapse" bordercolorlight="#000000" bordercolordark="#000000">
	<tr>
		<td align="center" bgcolor="#000000" width="12%"><font color="#FFFFFF">Version</font></td>
		<td align="center" bgcolor="#000000" width="88%"><font color="#FFFFFF">
		Vision</font></td>
	</tr>
	<tr>
		<td valign="top" align="center" width="12%">1.0</td>
		<td valign="top" width="88%">
		<ul>
			<li>Implement the portable subset of the .NET framework (i.e. ECMA CLI)</li>
			<li>Major components:<ul>
				<li>Corlib (.NET mscorlib.dll)</li>
				<li>System (.NET System.dll)</li>
				<li>Xml (.NET System.Xml.dll)</li>
			</ul>
			</li>
		</ul>
		</td>
	</tr>
	<tr>
		<td valign="top" align="center" width="12%">2.0</td>
		<td valign="top" width="88%">
		<ul>
			<li>Implement windows client development technologies</li>
			<li>Major components<ul>
				<li>Drawing (.NET System.Drawing.dll)</li>
				<li>Winforms (.NET System.Windows.Forms.dll)</li>
				<li>Data (.NET System.Data.dll)</li>
			</ul>
			</li>
		</ul>
		</td>
	</tr>
</table>
<p>The latest released version is 0.2. Version 1.0 is expected to release in 2004.</p>
<h2>Getting started</h2>
<p>Currently ACF is developed under Visual C++ 2003, you&#39;d better get it before 
we move on (if you are still using Visual C++ 6.0, throw it away since it is not 
very standards conformant and its template support is very limited). The first step 
will be to build ACF if not done before. For example, to build Corlib, 
open Corlib.sln (under &quot;{...}\Acf\src\Corlib&quot;, where {...} is the directory which 
contains ACF) with Visual Studio and build it. Like using other C++ libraries, you 
need to setup the include and library directories in your development environment 
before using ACF in your applications. The include directory for Corlib is &quot;{...}\Acf\src\Corlib&quot;, 
library directory is &quot;{...}\Acf\lib&quot;.</p>
<p>The &quot;hello world&quot; program can be written as follows:</p>
<pre><font color="#0000FF">#include</font> <font color="#FF0000">&lt;AcfCorlib.h&gt;</font>

<font color="#0000FF">int</font> main() {
    Acf::Console::WriteLine(<font color="#FF0000">L&quot;hello, world&quot;</font>);
}
</pre>
<p>To compile this program, you need to turn on &quot;treat wchar_t as built-in type&quot; 
and &quot;enable runtime type info&quot; compiler options, and link to the multithreaded CRT. 
This is required for all ACF projects.</p>
<p>ACF is organized into a number of namespaces, following the design of the .NET 
framework. The <span class="inlinecode">Acf</span> namespace corresponds to the
<span class="inlinecode">System</span> namespace in the .NET framework.
<span class="inlinecode">AcfCorlib.h</span> is the header file for the Corlib. Before 
we can write more useful applications, let&#39;s look into the type system of ACF.</p>
<h2>Basic type system</h2>
<p>There are some significant differences between the C++ type system and the C#/CLI 
type system, this affects how ACF type system is implemented.</p>
<p>C++ does not have a unified type system. Primitive types are &quot;magic&quot;; types are 
not required to inherit from a common root; and MI is allowed. C++ also has a very 
flexible memory model, the developers control how and when to allocate/free memory.</p>
<p>C#/CLI has an unified type system. All types directly or indirectly inherit from
<span class="inlinecode">System.Object</span>; MI is not allowed, but a type can 
implement multiple interfaces. Types can be value types or reference types. Instances 
of value types directly contain data; instances of reference types are allocated 
on the GC heap, and are automatically reclaimed. The translation between value types 
and reference types is called boxing/unboxing, which is handled by the compiler 
and the runtime.</p>
<p>ACF tries to emulate the C#/CLI type system on C++ and at the same time retain 
performance. The result is a hybrid type system. In ACF, types include reference 
types and other types. Reference types are allocated on the heap, and managed using 
reference count (like COM). Reference types are required to inherit from a single 
root - <span class="inlinecode">Acf::Object</span>. MI is only used to implement 
interfaces, and all reference interfaces are required to inherit from
<span class="inlinecode">Acf::InterfaceBase</span>. Other types include the primitive 
types (e.g. int, float), enum types and other C++ structures and classes. The following 
diagram shows the basic object model (green classes are value types, blue classes 
are reference types):</p>
<p><img src="objmod.gif"></p>
<p>In ACF, there is no automatically boxing/unboxing since it requires compiler 
and runtime support. Developers have to define the value class and reference class 
separately and handle the boxing/unboxing requests (in C#/CLI there is only one 
type, and boxing/unboxing are automatically handled). For example,
<span class="inlinecode">Int32</span> is a value type and does not have a base. 
It has an instance int field and provides methods for parsing and formatting. The
<span class="inlinecode">Int32Object</span> reference type has an instance
<span class="inlinecode">Int32</span> field and inherits from
<span class="inlinecode">Acf::Object</span> and implements interfaces such as
<span class="inlinecode">IFormattable</span>. (ACF uses X and XObject naming conversion 
to distinguish value types and their corresponding reference types, another example 
is <span class="inlinecode">Acf::Guid</span> and <span class="inlinecode">Acf::GuidObject</span>.)</p>
<p>The example:</p>
<pre><font color="#0000FF">int</font> main() {
    <font color="#0000FF">int</font> i = <font color="#800000">123</font>;
    ObjectPtr o = <font color="#0000FF">box</font>(i); <font color="#008000">// boxing</font>
    <font color="#0000FF">int</font> j = <font color="#0000FF">unbox</font>&lt;<font color="#0000FF">int</font>&gt;(o); <font color="#008000">// unboxing</font>
}
</pre>
<p>shows how boxing and unboxing are used. The <span class="inlinecode">box</span> 
and <span class="inlinecode">unbox&lt;T&gt;</span> functions are template functions under
<span class="inlinecode">Acf</span> namespace. The default implementation of
<span class="inlinecode">box</span> returns an instance of
<span class="inlinecode">Acf::Boxed&lt;T&gt;</span> which inherits from
<span class="inlinecode">Acf::Object</span> and acts as an object box. The
<span class="inlinecode">box</span> and <span class="inlinecode">unbox&lt;T&gt;</span> 
functions should be overloaded for user-defined types that have separate value class 
and reference class definitions (for example, <span class="inlinecode">Int32</span> 
and <span class="inlinecode">Int32Object</span>).</p>
<p>In ACF, all reference types are allocated on the heap via operator
<span class="inlinecode">new</span>. The <span class="inlinecode">new</span> operator 
is overloaded so that it throws <span class="inlinecode">Acf::OutOfMemoryException</span> 
when memory allocation fails. On successful allocation, the returned memory is cleared 
so there are no random bits. As stated, ACF uses reference count to manage object 
lifetime (all interfaces share the same reference count with their owner objects). 
When holding an object or an interface, you should call <span class="inlinecode">
AddRef</span>; when you are done you should call <span class="inlinecode">Release</span>. 
An object has an initial reference count 0 and is freed when its reference count 
goes back to 0. A smart pointer class, <span class="inlinecode">RefPtr&lt;T&gt;</span>, 
is designed to do the <span class="inlinecode">AddRef/Release</span> jobs automatically. 
As a common design philosophy, <span class="inlinecode">RefPtr&lt;T&gt;</span> is treated 
as strong reference, and raw C++ pointer is treated as weak reference. We need to 
distinguish strong reference and weak reference because the reference count approach 
has problem dealing with cyclic reference. For example, if object A has a strong 
reference to object B, and object B has a strong reference back to object A, then 
these two objects form a cyclic reference and both will never be freed. This problem 
can be solved by letting B hold a weak reference to A (or reverse, depending on 
the scenario).</p>
<p>The following example shows how to define and use reference type:</p>
<pre><font color="#0000FF">#include </font><font color="#FF0000">&lt;AcfCorlib.h&gt;</font>
<font color="#0000FF">using namespace </font>Acf;

<font color="#0000FF">class</font> Person : <font color="#0000FF">public</font> <font color="#0000FF">Object</font> {
<font color="#0000FF">public</font>:
    StringPtr Name;
    <font color="#0000FF">int</font> Age;
    
    Person() {
    }
    
<font color="#0000FF">protected</font>:
    <font color="#0000FF">virtual</font> ~Person() {
    }
};

<font color="#0000FF">int</font> main() {
    StringPtr name = <font color="#0000FF">new</font> String(<font color="#FF0000">L&quot;Foo&quot;</font>);

    RefPtr&lt;Person&gt; person = <font color="#0000FF">new</font> Person();
    person-&gt;Name = name;
    person-&gt;Age = <font color="#800000">25</font>;

    Console::WriteLine(<font color="#FF0000">L&quot;Name: {0}, Age: {1}&quot;</font>, person-&gt;Name, <font color="#0000FF">str</font>(person-&gt;Age));
}</pre>
<p>The class Person is a reference type and inherits from
<span class="inlinecode">Acf::Object</span>. It has two instance fields, Name (string) 
and Age (int). <span class="inlinecode">StringPtr</span> is a typedef of
<span class="inlinecode">RefPtr&lt;String&gt;</span>. The destructor is protected so this 
type cannot be allocated on stack (reference types shall always be allocated on 
the heap).</p>
<p>In the main function, the first statement defines and allocates a new string 
instance. Next a new person instance is allocated and its fields are changed. Then
<span class="inlinecode">Console::WriteLine</span> is used to format and print the 
person&#39;s name and age (the format string is defined by the .NET framework).</p>
<h2>Exceptions</h2>
<p>ACF uses exceptional handling as its basic error raising and handling mechanism. 
In the .NET framework, exceptions are also reference types and collected by GC. 
In ACF, exceptions are value types. This is because in C++, the preferred way to 
throw and catch exceptions is <span class="inlinecode">throw MyException()</span> 
and <span class="inlinecode">catch (const MyException&amp; e)</span>.
<span class="inlinecode">Acf::Exception</span> is the base class for all exceptions. 
Common exception classes include <span class="inlinecode">ArgumentNullException</span>,
<span class="inlinecode">IOException</span>, <span class="inlinecode">FormatException</span>, 
etc.</p>
<h2>Arrays and collections</h2>
<p>Arrays and collections in ACF are different from the .NET framework ones, because 
C++ provides good template and template specialization support (especially partial 
specialization).</p>
<p><span class="inlinecode">Array&lt;T&gt;</span> is the array class in ACF (currently 
multidimensional arrays are not supported). The actual class declaration is
<span class="inlinecode">Array&lt;T, Tr&gt;</span>, where <span class="inlinecode">Tr</span> 
is the collection traits class (there are default implementations for most classes). 
The collection traits control how to pass parameters, how to clear elements, how 
to compare two elements and how to generate hash code. This technique is used by 
all ACF collection classes and interfaces.</p>
<p>Here are two array examples:</p>
<pre>RefPtr&lt;Array&lt;<font color="#0000FF">int</font>&gt; &gt; array1 = Array&lt;<font color="#0000FF">int</font>&gt;::Build(<font color="#800000">3</font>, <font color="#800000">1</font>, <font color="#800000">2</font>, <font color="#800000">5</font>, <font color="#800000">4</font>);
Array&lt;<font color="#0000FF">int</font>&gt;::Sort(array1);

RefPtr&lt;Array&lt;StringPtr&gt; &gt; array2 = <font color="#0000FF">new</font> Array&lt;StringPtr&gt;(<font color="#800000">2</font>);
array2-&gt;Item[<font color="#800000">0</font>] = <font color="#0000FF">str</font>(<font color="#FF0000">L&quot;hello&quot;</font>);
array2-&gt;Item[<font color="#800000">1</font>] = <font color="#0000FF">str</font>(<font color="#FF0000">L&quot;world&quot;</font>);
</pre>
<p>The first example builds an int array with 5 elements and sorts it. The second 
example creates a string array with two elements and sets the elements. the
<span class="inlinecode">Item[0]</span> syntax is a Visual C++ language extension 
which represents an indexed property. It is translated into
<span class="inlinecode">array2-&gt;set_Item(0, str(L&quot;hello&quot;))</span> at compile time.</p>
<p>The other collection classes and interfaces in ACF (under namespace
<span class="inlinecode">Acf::Collections</span>) is just like the .NET framework 
ones, except they are template based. Here are some examples:</p>
<pre>RefPtr&lt;List&lt;<font color="#0000FF">int</font>&gt; &gt; list = <font color="#0000FF">new</font> List&lt;<font color="#0000FF">int</font>&gt;();
list-&gt;Add(<font color="#800000">10</font>);
list-&gt;Add(<font color="#800000">20</font>);

RefPtr&lt;Dictionary&lt;StringPtr, <font color="#0000FF">int</font>&gt; &gt; map = <font color="#0000FF">new</font> Dictionary&lt;StringPtr, <font color="#0000FF">int</font>&gt;();
map-&gt;Item[<font color="#0000FF">str</font>(<font color="#FF0000">L&quot;s1&quot;</font>)] = 1;
map-&gt;Item[<font color="#0000FF">str</font>(<font color="#FF0000">L&quot;s2&quot;</font>)] = 10;
</pre>
<p>C# has a <span class="inlinecode">foreach</span> statement to enumerate over 
arrays and collections and many developers like it very much. ACF defines a
<span class="inlinecode">FOREACH</span> macro to emulate this feature. For example, 
given an array which stores int, we can enumerate the array as follows:</p>
<pre>FOREACH (<font color="#0000FF">int</font>, n, array) {
    Console::WriteLine(n);
}
</pre>
<h2>Delegates and events</h2>
<p>Delegates and events are so attractive features of C# and the .NET framework 
that ACF definitely cannot miss them.</p>
<p>The delegate definition in ACF is quite different from C#/CLI. For example, the
<span class="inlinecode">EventHandler</span> delegate definition in C# is as follows:</p>
<pre><font color="#0000FF">delegate void </font>EventHandler(<font color="#0000FF">object</font> sender, EventArgs e);</pre>
<p>In ACF it is like:</p>
<pre><font color="#0000FF">typedef</font> Delegate2&lt;<font color="#0000FF">void</font>, <font color="#0000FF">Object</font>*, EventArgs*&gt;   EventHandler;</pre>
<p>Here <span class="inlinecode">DelegateN&lt;R, P1, P2, ..., Pn&gt;</span> is the delegate 
class in ACF, where <span class="inlinecode">N</span> is the number of the function 
parameters and <span class="inlinecode">R</span> is the function return type. To 
invoke a delegate, call the instance method <span class="inlinecode">Invoke</span> 
with the function parameters.</p>
<p>In C# it is very easy to define and consume events, but in ACF it&#39;s a little 
complex since there is no compiler support. To define an event, use the
<span class="inlinecode">ACF_DECLARE_EVENT</span> macro.</p>
<p>Here is an example on how to use delegates and events in ACF:</p>
<pre><font color="#0000FF">typedef</font> Delegate2&lt;<font color="#0000FF">void</font>, <font color="#0000FF">Object</font>*, EventArgs*&gt;   EventHandler;
<font color="#0000FF">typedef</font> RefPtr&lt;EventHandler&gt;   EventHandlerPtr;

<font color="#0000FF">class</font> Button : <font color="#0000FF">public</font> <font color="#0000FF">Object</font> {
<font color="#0000FF">public</font>:
    ACF_DECLARE_EVENT(EventHandler, Click)

<font color="#0000FF">protected</font>:
    <font color="#0000FF">void</font> OnClick(EventArgs* e) {
        <font color="#0000FF">if</font> (<font color="#0000FF">this</font>-&gt;Click != <font color="#0000FF">null</font>)
            <font color="#0000FF">this</font>-&gt;Click-&gt;Invoke(<font color="#0000FF">this</font>, e);
    }
};

<font color="#0000FF">class</font> Form1 : <font color="#0000FF">public</font> Object {
<font color="#0000FF">private</font>:
    RefPtr&lt;Button&gt; _button;

<font color="#0000FF">public</font>:
    Form1() {
        <font color="#0000FF">this</font>-&gt;_button = <font color="#0000FF">new</font> Button();

        EventHandlerPtr h1 = <font color="#0000FF">new</font> EventHandler(<font color="#0000FF">this</font>, Form1::ButtonClickHandler);
        <font color="#0000FF">this</font>-&gt;_button-&gt;add_Click(h1);

        EventHandlerPtr h2 = <font color="#0000FF">new</font> EventHandler(Form1::StaticButtonClickHandler);
        <font color="#0000FF">this</font>-&gt;_button-&gt;add_Click(h2);
    }

<font color="#0000FF">private</font>:
    <font color="#0000FF">void</font> ButtonClickHandler(<font color="#0000FF">Object</font>* sender, EventArgs* e) {
        std::cout &lt;&lt; <font color="#FF0000">&quot;Button clicked!&quot;</font> &lt;&lt; std::endl;
    }

    <font color="#0000FF">static void </font>StaticButtonClickHandler(<font color="#0000FF">Object</font>* sender, EventArgs* e) {
        std::cout &lt;&lt; <font color="#FF0000">&quot;Static: Button clicked!&quot;</font> &lt;&lt; std::endl;
    }
};
</pre>
<p>The <span class="inlinecode">ACF_DECLARE_EVENT</span> macro actually generates 
the following code:</p>
<pre><font color="#0000FF">class</font> Button : <font color="#0000FF">public</font> <font color="#0000FF">Object</font> {
<font color="#0000FF">private</font>:	
    RefPtr&lt;EventHandler&gt; Click;
    
<font color="#0000FF">public</font>:
    <font color="#0000FF">void</font> add_Click(EventHandler* h) {
        LOCK (<font color="#0000FF">this</font>)
            <font color="#0000FF">this</font>-&gt;Click = EventHandler::Combine(<font color="#0000FF">this</font>-&gt;Click, h);
    }
    <font color="#0000FF">void</font> remove_Click(EventHandler* h) {
        LOCK (<font color="#0000FF">this</font>)
            <font color="#0000FF">this</font>-&gt;Click = EventHandler::Remove(<font color="#0000FF">this</font>-&gt;Click, h);
    }
};</pre>
<p>In <span class="inlinecode">Form1</span>&#39;s constructor, two delegates are created, 
one attaches to a static method and another attaches to an instance method. For 
the instance method, the delegate also need a reference to the object (here it is
<span class="inlinecode">Form1</span>). Since <span class="inlinecode">Form1</span> 
has a strong reference to <span class="inlinecode">Button</span>, and
<span class="inlinecode">Button</span> has a strong reference to
<span class="inlinecode">Click</span>, so, if <span class="inlinecode">Click</span> 
has a strong reference to <span class="inlinecode">Form1</span>, then a cyclic reference 
is formed. However, in other cases the delegates may really need strong references 
to the objects. So, the constructors of the delegate classes are overloaded for 
both <span class="inlinecode">T*</span> and <span class="inlinecode">RefPtr&lt;T&gt;</span>. 
If you pass a <span class="inlinecode">T*</span> when constructing a delegate (typically 
using the <span class="inlinecode">this</span> pointer), the delegate will holds 
a weak reference to the object. Otherwise it&#39;ll hold a strong reference.</p>
<h2>Strings and text</h2>
<p>The <span class="inlinecode">String</span> and <span class="inlinecode">StringBuilder</span> 
classes provide basic string manipulations. The <span class="inlinecode">Acf::Text
</span>namespace also provides classes for encoding and decoding text, as the .NET 
framework. Here is a simple example:</p>
<pre>StringPtr s = String::Format(<font color="#FF0000">L&quot;Text: {0} {1}&quot;</font>, s1, obj);

EncodingPtr enc = Encoding::get_Default();
RefPtr&lt;Array&lt;<font color="#0000FF">byte</font>&gt; &gt; bytes = enc-&gt;GetBytes(s);
</pre>
<p>The <span class="inlinecode">str</span> function converts numerical values and 
C-style strings to <span class="inlinecode">String</span>.</p>
<pre><font color="#0000FF">int</font> a = <font color="#800000">10</font>;
<font color="#0000FF">float</font> b = <font color="#800000">15.2</font>;
<font color="#0000FF">const char</font>* c = <font color="#FF0000">"hello"</font>;

StringPtr s = String::Format(<font color="#FF0000">L&quot;{0}{1}{2}&quot;</font>, <font color="#0000FF">str</font>(a), <font color="#0000FF">str</font>(b), <font color="#0000FF">str</font>(c));</pre>
<h2>I/O</h2>
<p>The <span class="inlinecode">Acf::IO</span> namespace contains classes for reading 
and writing streams and files (currently ACF does not support asynchronous file 
I/O).</p>
<p>For example, to read text from a file, you can write code as follows:</p>
<pre>StringPtr path = <font color="#0000FF">new</font> String(<font color="#FF0000">L&quot;C:\in.txt&quot;</font>);
StreamReaderPtr reader = <font color="#0000FF">new</font> StreamReader(path);
StringPtr text = reader-&gt;ReadToEnd();
</pre>
<p>ACF supports basic streams including <span class="inlinecode">FileStream</span> 
and <span class="inlinecode">MemoryStream</span>, and readers/writers including
<span class="inlinecode">BinaryReader/BinaryWriter</span>,
<span class="inlinecode">TextReader/TextWriter</span>, <span class="inlinecode">
StreamReader/StreamWriter</span> and <span class="inlinecode">StringReader/StringWriter</span>.</p>
<p>ACF also supports simple file system management via <span class="inlinecode">
Path</span>, <span class="inlinecode">File</span> and <span class="inlinecode">Directory</span> 
classes.</p>
<h2>Threading</h2>
<p>ACF provides basic support for writing multithreaded applications. The following 
code shows how to create and start worker threads:</p>
<pre><font color="#0000FF">static void </font>WorkerThreadProc() {
    ...
}

<font color="#0000FF">class</font> MyObject : <font color="#0000FF">public</font> Object {
<font color="#0000FF">public</font>:
    <font color="#0000FF">void</font> WorkerThreadProc() {
        ...
    }
};

<font color="#0000FF">int</font> main() {
    ThreadPtr thread1 = <font color="#0000FF">new</font> Thread(WorkerThreadProc);
    thread1-&gt;Start();

    RefPtr&lt;MyObject&gt; obj = <font color="#0000FF">new</font> MyObject();

    ThreadStartPtr start = <font color="#0000FF">new</font> ThreadStart(obj, MyObject::WorkerThreadProc);
    ThreadPtr thread2 = <font color="#0000FF">new</font> Thread(start);
    thread2-&gt;Start();

    ...
}
</pre>
<p>To synchronize data access, use the <span class="inlinecode">LOCK</span> macro 
or the <span class="inlinecode">Interlocked</span>, <span class="inlinecode">Monitor</span>,
<span class="inlinecode">AutoResetEvent</span>, <span class="inlinecode">ManualResetEvent</span> 
or <span class="inlinecode">Mutex</span> classes.</p>
<h2>History</h2>
<ul>
	<li>5/25/2004, version 0.2.</li>
	<li>4/25/2004, version 0.1.</li>
</ul>
<h2>Contact</h2>
<p>Your feedback and suggestions are key factors to make this framework better, please 
feel free to send them to Yingle Jia (<a href="mailto:yljia@msn.com">yljia@msn.com</a>). 
You can also visit his weblog at
			<a href="http://blogs.wwwcoder.com/yljia/">
			http://blogs.wwwcoder.com/yljia/</a>.</p>

</body>

</html>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
China China
Yingle Jia is a software engineer located in Beijing, China. He currently works at IBM CSDL (China Software Development Lab). His interests include C++/COM/C#/.NET/XML, etc. He likes coding and writing.

He is the creator of ACF (Another C++ Framework) project. See http://acfproj.sourceforge.net/.

He also has a blog at http://blogs.wwwcoder.com/yljia/

Comments and Discussions