Daily Archives: February 24, 2014
migration C#, Java, C++ (day 1)
This is day 1 of this series. I am covering some tricky basics between the two languages before we get more complicated. All should be self-explanatory. There is no clear structure yet. I just picked some examples that are worth mentioning.
There is a lot of code that cannot be written in C# or C++. Sometimes the differences are quite big. I am still trying to find a solution to show such properly in a comparison without just documenting each language by itself.
Arrays
// single-dimensional array int[] a1 = new int[5]; Console.WriteLine(a1.Length); // 5 // rectangular array int[,] a2 = new int[3, 4]; Console.WriteLine(a2.Length); // 12 Console.WriteLine(a2.GetUpperBound(0)); // 2 Console.WriteLine(a2.GetUpperBound(1)); // 3 // jagged arrays int[][] a3 = new int[5][]; for (int i = 0, n = a3.Length; i < n; i++) a3[i] = new int[i + 3]; Console.WriteLine(a3.Length); // 5 Console.WriteLine(a3[3].Length); // 6 Console.WriteLine(a3.GetUpperBound(0)); // 4
// single-dimensional array int[] a1 = new int[5]; System.out.println(a1.length); // 5 // rectangular array int[][] a2 = new int[3][4]; System.out.println(a2.length); // 3 System.out.println(a2[0].length); // 4 // jagged arrays int[][] a3 = new int[5][]; for (int i = 0, n = a3.length; i < n; i++) a3[i] = new int[i + 3]; System.out.println(a3.length); // 5 System.out.println(a3[3].length); // 6
// single-dimensional array int* a0 = new int[5]; // Size cannot be determined. Use std::vector. int a1[5]; cout << sizeof(a1) << endl; // 20 bytes cout << sizeof(a1)/sizeof(a1[0]) << endl; // 5 elements // rectangular array unsigned int a2[3][4]; cout << "int[3][4]: " << sizeof(a2) << endl; // 48 cout << " int[4]: " << sizeof(*a2) << endl; // 16 cout << " int: " << sizeof(**a2) << endl; // 4 cout << " a2: " << a2 << endl; // 0x28fed0 cout << "(*a2) + 1: " << (*a2) + 1 << endl; // 0x28fed4 (4 higher) cout << " a2 + 1: " << a2 + 1 << endl; // 0x28fee0 (16 higher) // jagged arrays int** a3 = new int*[5]; for(size_t i = 0; i < 5; ++i) a3[i] = new int[i + 3]; for(size_t i = 0; i < 5; ++i) delete[] a3[i]; delete[] a3;
Pointers
// call by reference vs. call by value void CallByValue(int x) { x = 6; } void CallByRefernce1(ref int x) { x = 1; } void CallByRefernce2(out int x) { x = 2; } public int func(int x) { return x; } int h = 3; CallByValue(h); Console.WriteLine(h); // 3 CallByRefernce2(out h); Console.WriteLine(h); // 2 CallByRefernce1(ref h); Console.WriteLine(h); // 1 // this is a simple delegate (not a pointer) Func<int, int> f = func; Console.WriteLine(f(5)); // 5
public final class delegateWrapper<T> { public T invoke(T t) { return t; } } // class public final class boxingWrapper<T> { public T value; public boxingWrapper(T xValue) { value = xValue; } } // class private void CallByValue(int x) { x = 6; } private void CallByRefernce(boxingWrapper<Integer> x) { x.value = 1; } int h = 3; boxingWrapper<Integer> lWrapper = new boxingWrapper<Integer>(h); CallByValue(h); // 3 System.out.println(h); CallByRefernce(lWrapper); h = lWrapper.value; // 1 System.out.println(h); // there are no pointers or delegates in Java delegateWrapper<Integer> lDelegate = new delegateWrapper<Integer>(); h = lDelegate.invoke(5); System.out.println(h); // 5
// call by reference vs. call by value void CallByValue(int x) { x = 6; } void CallByRefernce(int &x) { x = 1; } int func(int x) { return x; } int h = 3; CallByValue(h); cout<<h<<endl; // 3 CallByRefernce(h); cout<<h<<endl; // 1 // pointer to a method int (*f)(int) = 0; f = &func; cout<< f(5) << " " << (*f)(5) << endl; // 5 5 // pointer to integers (not available in C#) int *p1; // pointer to an integer int p2[3]; // an array of 3 integers int *p3[3]; // an array of 3 pointers to integers int (*p4)[3]; // a pointer to an array of 3 integers int *(&p5)[3] = p3; // a reference to an array of 3 pointers to integers int *(*p6[3])[4]; // an array of 3 pointers to an array of 4 pointers to integers int **(*p7[2])[3]; // an array of 2 pointers to an array of 3 pointers to pointers to integers
Strings
string s = "Hello World!"; // Unicode (24 bytes) Console.WriteLine(s.Length); // 12 if (s.CompareTo("abc") > 0) Console.WriteLine("larger"); for (int i = 0, n = s.Length; i < n; i++) Console.Write(s[i] + " "); Console.WriteLine(); foreach (char lChar in s) Console.Write(lChar + " "); Console.WriteLine(); int lPosition = s.IndexOf("ll", 0); s = s.Remove(lPosition, 2) + " / " + s.Substring(lPosition, 2); Console.WriteLine(s);
String s = "Hello World!"; // Unicode (24 bytes) System.out.println(s.length()); // 12 if (s.compareTo("abc") > 0) System.out.println("larger"); for (int i = 0, n = s.length(); i < n; i++) System.out.print(s.charAt(i) + " "); System.out.println(); char[] lChars = s.toCharArray(); for (char lChar : lChars) System.out.print(lChar + " "); System.out.println(); int lPosition = s.indexOf("ll", 0); // there is no remove, so we need to simulate it String h = s.substring(0, lPosition) + s.substring(lPosition + 2); s = h + " / " + s.substring(lPosition, lPosition + 2); System.out.println(s);
// strings (null terminated ASCII codes) string s = "Hello World!"; // == {’H’, ’e’, ’l’, ’l’, ’o’, ’ ’, ’W’, ’o’, ’l’, ’d’, ’!’, ’\0’} cout<< s << ", length: " << s.length() << endl; cout<< sizeof(s) << endl; // pointer size if (s < "abc") cout << "abc is larger" << endl; // operator overloaded in string.h for (int i = 0;s[i] != '\0'; i++) cout << s[i] << " "; cout << endl; for (int i = 0, n = s.length(); i < n; i++) cout << s.at(i) << " "; // includes boundary checks and exception handling cout << endl; for (char &c : s) cout << c << " "; // includes boundary checks and exception handling cout << endl; int lPosition = s.find("ll", 0); s = s.erase(lPosition, 2) + " / " + s.substr(lPosition, 2); cout << s << endl; // wstring holds unicode characters // (wchar_t is 2 bytes on Windows, 4 bytes on Linux) const wstring lWString = L"Hello wide world :)"; wcout<<lWString<<endl; // direct output string lString(lWString.begin(), lWString.end()); cout<<lString<<endl;
#define
// preprocessor #define is used to set flags #if DEBUG Console.WriteLine("DEBUG CODE"); try { throw new Exception(); } catch (Exception ex) { Console.WriteLine(ex.StackTrace); } #else Console.WriteLine("PROD CODE"); #endif
public static boolean DEBUG = true; // There are no preprocessors in Java. // To get as close as possible to the idea of preprocessors you // can use public static variables or Dependency Injection. public void test() { if (DEBUG) { System.out.println("DEBUG CODE"); try { throw new RuntimeException(); } catch (RuntimeException ex) { for (StackTraceElement x : ex.getStackTrace()) System.out.println(x.toString()); } } else System.out.println("PROD CODE"); }
// preprocessor #define #define OMG "Oh my god!\n" cout << OMG << endl; #define add(a, b, c) a + b + c + 1 cout << add(1, 2, 3) << endl; // 7 #define DEBUG #ifdef DEBUG cout << "DEBUG CODE" << endl; #else count << "PROD CODE" << endl; #endif cout << endl; cout << "This is the line " << __LINE__ << " of file " << __FILE__ << endl; cout << "Compilation date " << __DATE__ << " " << __TIME__ << endl;
struct vs. class
struct MyStruct { public double x; } // value type class MyClass { public double x; } // reference type MyStruct lStruct1 = new MyStruct(); MyStruct lStruct2 = lStruct1; // creates a copy of lStruct1 lStruct2.x = 1.0; lStruct1.x = 99.9; Console.WriteLine(lStruct2.x); // 1.0 ! MyClass lClass1 = new MyClass(); MyClass lClass2 = lClass1; // only assigns the reference lClass2.x = 1.0; lClass1.x = 99.9; Console.WriteLine(lClass2.x); // 99.9 !
// there are no user-defined value types like struct in Java public class MyClass { public double x; } private MyClass lClass1 = new MyClass(); private MyClass lClass2 = lClass1; // assigns the reference lClass2.x = 1.0; lClass1.x = 99.9; System.out.println(lClass2.x); // 99.9
// Structs in C++ are like classes. // The main difference is that the default for structs is public, whereas the default for classes is private. // Some people say that structs are for data (no methods) only. This is not true. Both can have methods.
Cast Operations
public class Dog { } public class Husky : Dog { } public class StyleGuide { } // cast operations double pi = 3.14159265; int lInt = (int)pi; double d = lInt; Console.WriteLine(d); // 3.0 Dog lDog = new Husky(); Husky lHusky = lDog as Husky; if (lHusky != null) Console.WriteLine("A husky is a dog"); StyleGuide lStyle = new StyleGuide(); //lHusky = (Husky)lStyle; // won't compile
public class Dog { } public class Husky extends Dog { } public class StyleGuide { } double pi = 3.14159265; int lInt = (int)pi; double d = lInt; System.out.println(d); // 3.0 Dog lDog = new Husky(); Husky lHusky = (Husky)lDog; if (lHusky != null) System.out.println("A husky is a dog"); StyleGuide lStyle = new StyleGuide(); // lHusky = (Husky)lStyle; // won't compile
// cast operations double pi = 3.14159265; int lInt = static_cast<int>(pi); double d = lInt; cout<<d<<endl; // 3.0 Dog *lDog = new Husky(); Husky *lHusky = dynamic_cast<Husky*>(lDog); if (lHusky != 0) cout<<"A husky is a dog"<< endl; StyleGuide *lStyle; lHusky = dynamic_cast<Husky*>(lStyle); if (lHusky == 0) cout<<"A StyleGuide is not a dog"<< endl; const char* lConst = "Hello World"; char* lVariable = const_cast<char*>(lConst); long lAddress = 5165786; lDog = reinterpret_cast<Dog*>(lAddress); if (lDog != 0) cout<<"What a funny dog"<< endl;
Collections:List
List<string> lList = new List<string>(); lList.Add("hello"); lList.Add("world"); foreach (var lItem in lList) Console.WriteLine(lItem); lList.Clear(); lList = null;
java.util.ArrayList<String> lList = new java.util.ArrayList<String>(); lList.add("hello"); lList.add("world"); for (String lItem : lList) System.out.println(lItem); lList.clear(); lList = null;
vector<wstring> lList = vector<wstring>(); lList.push_back(L"hello"); lList.push_back(L"world"); for (wstring &lItem : lList) wcout << lItem << endl; lList.clear();
Our first class
using System; namespace DemoApp.ToCpp { public class StyleGuide : IDisposable { private bool _Disposed = false; public StyleGuide() { } private double PrivateFunc(string s) { return 5.3; } public int PublicFunc(string s) { return 0; } protected string ProtectedFunc(string s) { return s; } ~StyleGuide() { Dispose(false); } // deconstructors call Finalize() of the base class public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool xDisposing) { if (_Disposed) return; if (xDisposing) { // free objects } _Disposed = true; } // } // class } // namespace
package DemoApp.ToCpp; public class StyleGuide { public StyleGuide() {} private double PrivateFunc(String s) { return 5.3; } public final int PublicFunc(String s) { return 0; } protected final String ProtectedFunc(String s) { return s; } @Override protected void finalize() throws Throwable { // // FreeResourcesHere(); // super.finalize(); } // destructor } // class
#ifndef STYLEGUIDE_H #define STYLEGUIDE_H #include <iostream> #include <string> using namespace std; class StyleGuide { public: StyleGuide(); virtual ~StyleGuide(); int PublicFunc(string* s); protected: string ProtectedFunc(string* s); private: double PrivateFunc(string* s); }; #endif // STYLEGUIDE_H
#include "StyleGuide.h" StyleGuide::StyleGuide() {} StyleGuide::~StyleGuide() {} double StyleGuide::PrivateFunc(string *s) { return 5.3; } int StyleGuide::PublicFunc(string *s) { return 0; } string StyleGuide::ProtectedFunc(string *s) { return *s; }