Monday, August 23, 2010

C++/CLI - Basics by Example



continue with the Basics by Example; today's version of the post written in C++/CLI Enjoy!

You can copy and paste the code below in your favorite IDE/Editor and start playing and learning with it. This little "working" program will teach you the basics of the Programming Language.

There are some "comments" on the code added just to tell you what are or how are some features called. In case you want to review the theory, you can read my previous post, where I give a definition of each of the concepts mentioned on the code. You can find it here: http://carlosqt.blogspot.com/2010/08/new-series-languages-basics-by-example.html 


Greetings Program - Verbose
// CppCli Basics
#include "stdafx.h"  
using namespace System;  
  
namespace CppCliGreetProgram {  

 private ref class Greet { 
  // Fields or Attributes
  private: String ^message;
  private: String ^name;
  private: int loopMessage; 
  // Properties
  public: property String^ Message {
   public: String^ get() { return this->message; }
   public: void set(String^ val) { this->message = val; }
  }
  public: property String^ Name {
   public: String^ get() { return this->name; }
   public: void set(String^ val) { this->name = val; }
  }
  public: property int LoopMessage {
   public: int get() { return this->loopMessage; }
   public: void set(int val) { this->loopMessage = val; }
  }
  // Constructor
  public: Greet() {
   this->message = "";
   this->name = "";
   this->loopMessage = 0;
  }
  // Overloaded Constructor
  public: Greet(String^ message, String^ name, int loopMessage) {
   this->message = this->Capitalize(message);
   this->name = this->Capitalize(name);
   this->loopMessage = loopMessage;
  }    
  // Method 1
  private: String^ Capitalize(String^ val) {
   // "if-then-else" statement
   if (val->Length >= 1) {
    return val[0].ToString()->ToUpper() + val->Substring(1, val->Length - 1);
   }
   else {
    return "";
   }
  }
 
  // Method 2
  public: void Salute() {
   // "for" statement
   for (int i = 0; i < this->loopMessage; i++) {
    Console::WriteLine("{0} {1}!", this->message, this->name);
   }
  }
  // Overloaded Method 2.1
  public: void Salute(String^ message, String^ name, int loopMessage) {
   // "while" statement
   int i = 0;
   while(i < loopMessage) {
    Console::WriteLine("{0} {1}!", this->Capitalize(message), this->Capitalize(name));
    i++;
   }
  }
  // Overloaded Method 2.2
  public: void Salute(String^ name) {
   // "switch/case" statement
   DateTime^ dtNow = DateTime::Now;
   switch (dtNow->Hour) {
    case 6: case 7: case 8: case 9: case 10: case 11:
     this->message = "good morning,";
     break;
    case 12: case 13: case 14: case 15: case 16: case 17:
     this->message = "good afternoon,";
     break;
    case 18: case 19: case 20: case 21: case 22: 
     this->message = "good evening,";
     break;
    case 23: case 0: case 1: case 2: case 3: case 4: case 5: 
     this->message = "good night,";
     break;
    default:
     this->message = "huh?";
     break;
   }
   Console::WriteLine("{0} {1}!", this->Capitalize(this->message), this->Capitalize(name));
  }
 };
}

// Console Program
int main(array<System::String ^> ^args) {
 // Define object of type Greet 
    CppCliGreetProgram::Greet ^g;
    // Instantiate Greet. Call Constructor
    g = gcnew CppCliGreetProgram::Greet();
    // Call Set Properties
    g->Message = "hello";
    g->Name = "world";
    g->LoopMessage = 5;
    // Call Method 2
    g->Salute();
    // Call Overloaded Method 2.1 and Get Properties
    g->Salute(g->Message, "c++/CLI", g->LoopMessage);
    // Call Overloaded Method 2.2
    g->Salute("carlos");
            
    // Stop and exit
    Console::WriteLine(L"Press any key to exit...");
    Console::Read();
 return 0;
}

Greetings Program - Minimal
// CppCli Basics
#include "stdafx.h"  
using namespace System;  

ref class Greet {
 // Fields or Attributes
 String ^message;
 String ^name;
 int loopMessage; 
 // Properties
public: 
 property String^ Message {
  String^ get() { return message; }
  void set(String^ val) { message = val; }
 }
 property String^ Name {
  String^ get() { return name; }
  void set(String^ val) { name = val; }
 }
 property int LoopMessage {
  int get() { return loopMessage; }
  void set(int val) { loopMessage = val; }
 }
 // Constructor
 Greet() {
  message = "";
  name = "";
  loopMessage = 0;
 }
 // Overloaded Constructor
 Greet(String^ message, String^ name, int loopMessage) {
  this->message = Capitalize(message);
  this->name = Capitalize(name);
  this->loopMessage = loopMessage;
 }    
 // Method 1
private: 
 String^ Capitalize(String^ val) {
  // "if-then-else" statement
  if (val->Length >= 1) {
   return val[0].ToString()->ToUpper() + val->Substring(1, val->Length - 1);
  }
  else {
   return "";
  }
 }
 
 // Method 2
public: 
 void Salute() {
  // "for" statement
  for (int i = 0; i < loopMessage; i++) {
   Console::WriteLine("{0} {1}!", message, name);
  }
 }
 // Overloaded Method 2.1
 void Salute(String^ message, String^ name, int loopMessage) {
  // "while" statement
  int i = 0;
  while(i < loopMessage) {
   Console::WriteLine("{0} {1}!", Capitalize(message), Capitalize(name));
   i++;
  }
 }
 // Overloaded Method 2.2
 void Salute(String^ name) {
  // "switch/case" statement
  DateTime^ dtNow = DateTime::Now;
  switch (dtNow->Hour) {
   case 6: case 7: case 8: case 9: case 10: case 11:
    message = "good morning,";
    break;
   case 12: case 13: case 14: case 15: case 16: case 17:
    message = "good afternoon,";
    break;
   case 18: case 19: case 20: case 21: case 22: 
    message = "good evening,";
    break;
   case 23: case 0: case 1: case 2: case 3: case 4: case 5: 
    message = "good night,";
    break;
   default:
    message = "huh?";
    break;
  }
  Console::WriteLine("{0} {1}!", Capitalize(message), Capitalize(name));
 }
};

// Console Program
int main(array<System::String ^> ^args) {
    // Define and Instantiate object of type Greet. Call Constructor
    Greet ^g = gcnew Greet();
    // Call Set Properties
    g->Message = "hello";
    g->Name = "world";
    g->LoopMessage = 5;
    // Call Method 2
    g->Salute();
    // Call Overloaded Method 2.1 and Get Properties
    g->Salute(g->Message, "c++/CLI", g->LoopMessage);
    // Call Overloaded Method 2.2
    g->Salute("carlos");
            
    // Stop and exit
    Console::WriteLine(L"Press any key to exit...");
    Console::Read();
}

And the Output is:


















Auto-Implemented Properties in C++/CLI

As with C# and VB.NET, C++/CLI also has built in syntax to create auto-implemented properties. Auto-implemented properties enable you to quickly specify a property of a class without having to write code to Get and Set the property. The compiler will automatically create a private field to store the property variable in addition to creating the associated get and set procedures.

// That means that we can omit the Fields/Attributes declaration
   //and go directly to the properties
 
private:
 // Fields or Attributes
 /*String ^message;
 String ^name;
 int loopMessage;*/ 
public: 
 // Auto-Implemented Properties
 property String^ Message;
 property String^ Name;
 property int LoopMessage;  
 
// then, when ever you want to use them you get and set their value using the  properties only (just like with C#. The attributes are marked as: 
// ".field private string " (via reflector) and you cannot access it directly) 
// Let's see an example in our constructor
        // Constructor
 public: Greet() {
  this->Message = "";
  this->Name = "";
  this->LoopMessage = 0;
 }



Initializer Lists in Constructors in C++/CLI

A constructor initializer list is a syntax construct that allows the user to initialize attributes/fields of a class, as well as parent class fields, of a class without using assignments. Let's see an example:

ref class Greet {
 // Fields or Attributes
 String ^message;
 String ^name;
 int loopMessage; 
public: 
 // then, instead of the using assignments within the Constructor
 // public: Greet() {
 //  this->Message = "";
 //  this->Name = "";
 //  this->LoopMessage = 0;
 // }
 // we use 
 // Constructor with Initialization Lists
 Greet() : message(""), name(""), loopMessage(0) { 
 }
 // Overloaded Constructor with Initialization Lists
 // you can also call other methods during the initialization (ex: Capitalize)
 Greet(String^ message, String^ name, int loopMessage) : message(Capitalize(message)), name(Capitalize(name)), loopMessage(loopMessage) {
 }
 // Method 1
private: 
 String^ Capitalize(String^ val) {}
}; 

 // However, if you decide to use Auto-Implemented Properties, then you do not have attribute fields anymore (at least, not that you can directly access), so you might think that you can initialize the property. Right?
// Well, not really. If you do that as shown here below, you will get a compiler error.

ref class Greet {
 // Fields or Attributes
 String ^message;
 String ^name;
 int loopMessage; 
 // Properties
public: 
 property int AutoImplementedPro;
 // Constructor with Initialization Lists
 Greet() : message(""), name(""), loopMessage(0), AutoImplementedPro(1) {}

// You will get:
// Error 1 error C3137: 'AutoImplementedPro' : a property cannot be initialized I:\Dev\PRJ\CppCLI_Basics_Features\CppCLI_Basics_Features\CppCLI_Basics_Features.cpp 28 1 CppCLI_Basics_Features

1 comment: