Contents |
C++ declarations:
int x; // declare x of type int int x(7); // declare x of type int and initialize to 7 int x(); // declare FUNCTION x(void) => int int *x = new int(); // declare x of type int *
C++ weird scope resolution:
class foo {};
class bar {
int foo(); // a member function named like a class
//foo f; // syntax error : missing ';' before identifier 'f'
::foo f; // specify scope to avoid error
};
C++ pointer containers:
boost::ptr_map does not support abstract classes. boost::ptr_map can be emulated using a combination of std::map and boost::ptr_list (or another non-associative container).
Elements in boost::ptr_list cannot be removed or found by their address. See the Boost Pointer Container Library page for a workaround.
C++ algorithms:
C#:
class MyClass {
public string ToString() {
return "MyClass instance";
}
}
...
MyClass myClass = new MyClass();
System.Console.WriteLine("myClass: " + myClass.ToString());
C++:
#include <ostream>
namespace Some_namespace {
using std::ostream;
class My_class {
friend ostream & operator << (ostream &, const My_class &);
};
}
// Drop overloaded ostream operator in global namespace
ostream & operator <<(ostream & os,
const Some_namespace::My_class &my_class) {
return os << "My_class instance";
}
using namespace std;
int main() {
Some_namespace::My_class my_class;
cout << "my_class: " << my_class << endl;
}
Ruby:
class My_class
def to_s() "My_class instance" end
end
my_class = My_class.new
puts "my_class: " + my_class
C#:
using System.Collections.Generic;
using System.Text.RegularExpressions;
class RegexTest {
static void Main() {
List<string> words = new List<string>() {
"HEJ", "Hello", "yo" };
Regex acceptedWordRegex = new Regex("he.*", RegexOptions.IgnoreCase);
Regex wordSubstitutionRegex =
new Regex("(^.)e(.*)", RegexOptions.IgnoreCase);
foreach(string word in words) {
if(acceptedWordRegex.IsMatch(word)) {
string s = wordSubstitutionRegex.Replace(
word, "$2e$1");
System.Console.WriteLine(s);
}
}
}
}
C++:
#include <boost/regex.hpp>
#include <boost/foreach.hpp>
#include <iostream>
using namespace std;
int main() {
char *words[] = { "HEJ", "Hello", "yo" };
boost::regex accepted_word_regex("he.*", boost::regex::icase);
boost::regex word_substitution_regex("(^.)e(.*)", boost::regex::icase);
BOOST_FOREACH(char *word, words) {
if(regex_match(word, accepted_word_regex)) {
string s = regex_replace(string(word),
word_substitution_regex, string("\\2e\\1"),
boost::match_default);
cout << s << endl;
}
}
}
Ruby:
words = [ "HEJ", "Hello", "yo" ]
words.each { |word|
if word =~ /he.*/i then
puts word.gsub(/(^.)e(.*)/i,'\2e\1')
end
}
C++
#include <boost/filesystem.hpp>
using namespace boost::filesystem;
const path & my_path;
assert( exists( my_path ) );
directory_iterator end_itr; // default construction yields past-the-end
for(directory_iterator itr(my_path); itr != end_itr; ++itr )
cout << itr->filename() << endl;
C#:
using System.IO;
// ...
Directory.CreateDirectory("/tmp/filetest");
using (StreamWriter sw = new StreamWriter("/tmp/filetest/testfile")) {
sw.WriteLine("yo");
}
if(File.Exists("/tmp/filetest/testfile"))
Console.WriteLine("we have created a file");
C++:
// link with boost_filesystem and boost_system
#include "boost/filesystem.hpp"
#include <iostream>
#include <fstream>
using namespace boost::filesystem;
using namespace std;
int main() {
create_directory("/tmp/filetest");
ofstream file("/tmp/filetest/testfile");
file << "yo" << endl;
file.close();
if(exists("/tmp/filetest/testfile"))
cout << "we have created a file" << endl;
}
Ruby:
require 'fileutils'
include FileUtils
mkdir_p "/tmp/filetest"
IO.popen("/tmp/filetest/testfile") { |f| f.puts "yo" }
if File.exists?("/tmp/filetest/testfile") then
puts "we have created a file"
end
C++:
#include <boost/thread.hpp> #include <boost/date_time.hpp> using namespace boost; this_thread::sleep(posix_time::seconds(1.5f));
C++:
#include <boost/timer.hpp> boost::timer timer; // Time elapsed since construction. double elapsed_time__s = timer.elapsed();
C#:
using System.Collections.Generic; List<int> numbers(1); numbers.Add(10); numbers.Add(23); // reallocate
C++ with value semantics:
#include <vector> using std::vector; vector<int> numbers(1); numbers.push_back(10); numbers[1] = 23; // reallocate
C++ with pointer semantics:
#include <boost/ptr_container/ptr_vector.hpp>
using boost::ptr_vector;
struct Thing {
Thing(int x) : x_(x) {}
int x_;
};
ptr_vector<Thing> things(1);
things.push_back(new Thing(10));
things[1] = new Thing(23); // reallocate
Ruby:
numbers = Array.new(1) numbers.push(10) numbers[1] = 23
C++:
#include <list>
#include <algorithm>
using namespace std;
list<int> l;
l.push_back(4);
l.push_back(9);
l.remove(4); // list::remove both removes and erases
// Filter based upon arbitrary predicate. Note that due to a
// weirdness in C++98, you cannot use local classes as predicates.
struct Larger_than {
Larger_than(int value) : value(value) {}
inline bool operator() (int value_to_check) const {
return value_to_check > value;
}
int value;
};
l.remove_if(Larger_than(5)); // both removes and erases
struct Is_even {
inline bool operator() (int value_to_check) const {
return value_to_check % 2 == 0;
}
};
l.remove_if(Is_even());
// search for value
list<int>::iterator i = find(l.begin(), l.end(), 7);
if(i == l.end()) {
// couldn't find 7
}
else {
// found it
}
C#:
using System.Collections.Generic;
// ...
Dictionary<string, Thing> name2thing = new Dictionary<string, Thing>();
name2thing["thing 1"] = new Thing("hey");
name2thing["thing 2"] = new Thing("there");
name2thing.Remove("thing 1");
if(name2thing.ContainsKey("thing 1") { ... }
foreach(string s in name2thing.Keys) {
System.Console.WriteLine(name2thing[s].Name);
}
C++:
#include <map>
#include <string>
#include <iostream>
#include <boost/foreach.hpp>
using namespace std;
// ...
typedef map<string, Thing *> Name_2_thing;
typedef Name_2_thing::iterator Name_2_thing_iterator;
Name_2_thing name_2_thing;
name_2_thing["thing 1"] = new Thing("hey");
name_2_thing["thing 2"] = new Thing("there");
name_2_thing.erase("thing 1");
// find member
Name_2_thing_iterator i = name_2_thing.find("thing 1");
if(i == name_2_thing.end()) {
// handle error: no such key
}
else {
Thing * thing = i->second;
}
// delete member
Name_2_thing_iterator i = name_2_thing.find("thing 1");
if(i == name_2_thing.end()) {
// handle error: no such key
}
else {
name_2_thing.erase(i);
}
BOOST_FOREACH(Name_2_thing::value_type &i, name_2_thing) {
cout << i.second->get_name() << endl;
}
Ruby:
// ...
name_2_thing = {}
name_2_thing["thing 1"] = Thing.new("hey")
name_2_thing["thing 2"] = Thing.new("there")
name_2_thing.delete("thing 1")
if name_2_thing.has_key?("thing 1") then ... end
name_2_thing.each do |name,thing|
puts thing.name
end
C#:
namespace MyNamespace {
class MyClass {
int someValue;
MyClass(int someValue) {
this.someValue = someValue;
}
~MyClass() {
System.Console.WriteLine("destroyed.");
}
public int SomeValue {
get { return someValue; }
set { someValue = value; }
}
private void something() {}
static void Main() {
MyNamespace.MyClass mc = new MyNamespace.MyClass(7);
System.Console.WriteLine(mc.SomeValue);
}
}
}
C++:
#include <iostream>
namespace My_namespace {
class My_class {
public:
My_class(int some_value) : some_value(some_value) {}
~My_class() {
std::cout << "destroyed." << std::endl;
}
int some_value() { return some_value; }
void some_value(const int &new_value) { some_value = new_value; }
private:
void something() {}
int some_value;
}
};
int main() {
My_namespace::My_class mc = new My_namespace::My_class();
std::cout << mc->my_method() << std::endl;
delete mc;
}
Ruby:
module My_namespace
class My_class
attr_accessor :some_value
def initialize(some_value)
@some_value = some_value
end
def release_resources() # not destructor
puts "destroyed."
end
def something() end
end
end
mc = My_namespace::My_class.new(7)
puts mc.some_value
mc.release_resources() # manually calling cleanup method
C#:
class Something
C++:
Returning a new Thing could just as well be done using a raw pointer. The caller could then store the pointer in a smart pointer or deallocate using delete. However, it is not explicit in the interface that the caller has to handle resource deallocation.
Using shared_ptr forces the caller to handle the memory correctly.
#include <memory>
using namespace std;
class Thing {
public:
virtual ~Thing() { ... }
// Named ctor.
static shared_ptr<Thing> create_thing() {
return shared_ptr<Thing>( new Thing(7) );
}
// Named ctor.
static shared_ptr<Thing> create_special_thing() {
return shared_ptr<Thing>( new Thing(60) );
}
// Virtual copy ctor.
virtual shared_ptr<Thing> clone() {
return shared_ptr<Thing>( new Thing(* this) );
}
protected:
// Private ctor accessed by factory methods.
Thing(int x) : x_(x) { }
// Private copy ctor accessed by clone.
Thing( const Thing & other) : x_(other.x_) { }
private:
int x_;
};
class Thingie : public Thing {
public:
// Named ctor.
static shared_ptr<Thingie> create_thingie() {
return shared_ptr<Thingie>( new Thingie(70) );
}
// Virtual copy ctor.
virtual shared_ptr<Thing> clone() {
return shared_ptr<Thing>(new Thingie( * this ));
}
private:
// Private ctor accessed by factory methods.
Thingie( int x ) : Thing(x) { }
Thingie( const Thingie & other ) : Thing(other.x_) { }
};
int main() {
shared_ptr<Thing> t0 = Thing::create_thing();
shared_ptr<Thing> t1 = Thing::create_special_thing();
shared_ptr<Thing> t2 = t1->clone();
shared_ptr<Thing> t3 = Thingie::create_thing();
shared_ptr<Thing> t4 = t3->clone();
}
Ruby:
def do_stuff(unnamed_parameter, opts={})
opts = {:named_parameter => 8, :other_named_parameter => true}.merge(opts) # default argument values
if opts[:other_named_parameter] then
...
else
...
end
end
In C#, the Observer pattern is implemented as events.
C#:
class Subject {
public delegate void SomeEventHandler(int someValue);
public event SomeEventHandler SomeEvent;
protected void doSomething() {
if(SomeEvent != null) SomeEvent(7);
}
}
class Observer {
public Observer(Subject subject) {
subject.SomeEvent += myHandler;
}
void myHandler(int someValue) {
// ...
}
}
In C++, boost::signal implements the Observer pattern.
C++:
#include <boost/signal.hpp>
#include <boost/bind.hpp>
class Subject {
public:
boost::signal<void (int)> some_event;
protected:
void do_something() {
some_event(7);
}
};
class Observer {
public:
Observer(subject &subject) {
subject.some_event.connect(boost::bind(& observer::my_handler, this, _1));
}
void my_handler(int some_value) {
// ...
}
};
In Ruby, observer.rb implements the Observer pattern.
require 'observer'
class Subject
include Observable # mixin
def do_something
changed # note that our state has changed
notify_observers( 7 )
end
end
class Observer
class My_handler
# the invoked method must be 'update'
def update(some_value)
# ...
end
end
def initialize(subject)
subject.add_observer(My_handler.new)
end
end