Welcome to ACF (Another C++ Framework)

About ACF
Download
Using ACF
  ◦ Getting Started
  ◦ Code Examples
• Resources
  ◦ Project Space
  ◦ Weblog
  ◦ Forum
Development
Contact

The latest version is 0.3 (release date: 6/25/2004).

About ACF

What is ACF

ACF (Another C++ Framework), is a C++ framework designed to bring 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.

Why ACF

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.

The solution from Microsoft is managed C++. MC++ 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, MC++ 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 too huge for many applications. Second, C++ is already very complex and hard to learn and use, MC++ adds to it.

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 MC++ (for example, they always use String::Format to build formatted strings). 3) ACF also helps when porting code between C++ and C#.

Using ACF

Getting Started

Currently ACF is developed under Visual C++ 2003, you'd better get it before we move on. The first step will be to build ACF if not done before. For example, to build Corlib, open Corlib.sln (under "{...}\Acf\src\Corlib", 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. The include directory for Corlib is "{...}\Acf\src\Corlib", library directory is "{...}\Acf\lib".

The "hello world" program can be written as follows:

#include <AcfCorlib.h>

int main() {
    Acf::Console::WriteLine(L"hello, world");
}

To compile this program, you need to turn on "treat wchar_t as built-in type" and "enable runtime type info" compiler options, and link to the multithreaded CRT. This is required for all ACF projects.

ACF is organized into a number of namespaces, following the design of the .NET framework. The Acf namespace corresponds to the System namespace in the .NET framework. AcfCorlib.h is the header file for the Corlib.

Code Examples

Here are some code examples on using ACF. Please check the related reference documents for detailed information.

Using reference type

#include <AcfCorlib.h>
using namespace Acf;

class Person : public Object {
public:
    StringPtr Name;
    int Age;

    Person() {
    }
};

int main() {
    StringPtr name = new String(L"Foo");

    RefPtr<Person> person = new Person();
    person->Name = name;
    person->Age = 25;

    Console::WriteLine(L"Name: {0}, Age: {1}", 
        person->Name, str(person->Age));
}

Boxing/unboxing

int main() {
    int i = 123;
    ObjectPtr o = box(i); // boxing
    int j = unbox<int>(o); // unboxing

    // Modify the boxed object directly
    Boxed<Int32>* intObj = dynamic_cast<Boxed<Int32>*>(o.Pointer);
    intObj->Value = 20;
}

Arrays

RefPtr<Array<int> > array1 = Array<int>::Build(3, 1, 2, 5, 4);
Array<int>::Sort(array1);

FOREACH (int, n, array) {
    Console::WriteLine(n);
}
RefPtr<Array<StringPtr, 2> > array2D = new Array<StringPtr, 2>(10, 20);
array2D->SetValue(str(L"Hello"), 0, 0);
array2D->SetValue(str(L"world"), 0, 1);

Collections

RefPtr<List<StringPtr> > list = new List<StringPtr>();
list->Add(str(L"hello"));
list->Add(str(L"world"));

FOREACH (StringPtr, s, list) {
    Console::WriteLine(s);
}

Delegates and events

typedef Delegate2<void, Object*, EventArgs*>   EventHandler;
typedef RefPtr<EventHandler>   EventHandlerPtr;

class Button : public Object {
public:
    ACF_DECLARE_EVENT(EventHandler, Click)

protected:
    void OnClick(EventArgs* e) {
        if (this->Click != null)
            this->Click->Invoke(this, e);
    }
};

class Form1 : public Object {
private:
    RefPtr<Button> _button;

public:
    Form1() {
        this->_button = new Button();

        EventHandlerPtr h1 = new EventHandler(this, 
            Form1::ButtonClickHandler);
        this->_button->add_Click(h1);

        EventHandlerPtr h2 = new EventHandler(
            Form1::StaticButtonClickHandler);
        this->_button->add_Click(h2);
    }

private:
    void ButtonClickHandler(Object* sender, EventArgs* e) {
        std::cout << "Button clicked!" << std::endl;
    }

    static void StaticButtonClickHandler(Object* sender, EventArgs* e) {
        std::cout << "Static: Button clicked!" << std::endl;
    }
};

Strings and text

int a = 10;
float b = 15.2;
const char* c = "hello";    

StringPtr s = String::Format(L"{0}{1}{2}", str(a), str(b), str(c));

EncodingPtr enc = Encoding::get_Default();
RefPtr<Array<byte> > bytes = enc->GetBytes(s);

I/O

StringPtr path = new String(L"C:\in.txt");
StreamReaderPtr reader = new StreamReader(path);
StringPtr text = reader->ReadToEnd();

Threading

static void WorkerThreadProc() {
    ...
}

class MyObject : public Object {
public:
    void WorkerThreadProc() {
        ...
    }
};

int main()
{
    ThreadPtr thread1 = new Thread(WorkerThreadProc);
    thread1->Start();

    RefPtr<MyObject> obj = new MyObject();

    ThreadStartPtr start = new ThreadStart(obj, 
        MyObject::WorkerThreadProc);
    ThreadPtr thread2 = new Thread(start);
    thread2->Start();
}

Development

The project space is at http://sourceforge.net/projects/acfproj/.

The project development plan is as follows:

Version Vision
1.0
  • Implement the portable subset of the .NET framework (i.e. ECMA CLI)
  • Major components:
    • Corlib (.NET mscorlib.dll)
    • System (.NET System.dll)
    • Xml (.NET System.Xml.dll)
2.0
  • Implement windows client development technologies
  • Major components
    • Drawing (.NET System.Drawing.dll)
    • Winforms (.NET System.Windows.Forms.dll)
    • Data (.NET System.Data.dll)

Version 1.0 is expected to release in 2004. The exact date depends on how many people (dev/test) are involved. If you would like to contribute, please send an e-mail to Yingle Jia (yljia@msn.com), and include a short description of yourself and which features you are interested in (for example, Xml).

Contact

Your feedback and suggestions are key factors to make this framework better, please feel free to send them to Yingle Jia (yljia@msn.com). You can also visit his weblog at http://blogs.wwwcoder.com/yljia/.

SourceForge.net Logo