diff options
Diffstat (limited to 'c++.html.markdown')
| -rw-r--r-- | c++.html.markdown | 164 | 
1 files changed, 148 insertions, 16 deletions
| diff --git a/c++.html.markdown b/c++.html.markdown index 9f357b08..ff2a98fd 100644 --- a/c++.html.markdown +++ b/c++.html.markdown @@ -30,10 +30,9 @@ one of the most widely-used programming languages.  // C++ is _almost_ a superset of C and shares its basic syntax for  // variable declarations, primitive types, and functions. -// However, C++ varies in some of the following ways: -// A main() function in C++ should return an int, -// though void main() is accepted by most compilers (gcc, clang, etc.) +// Just like in C, your program's entry point is a function called +// main with an integer return type.  // This value serves as the program's exit status.  // See http://en.wikipedia.org/wiki/Exit_status for more information.  int main(int argc, char** argv) @@ -51,6 +50,8 @@ int main(int argc, char** argv)      return 0;  } +// However, C++ varies in some of the following ways: +  // In C++, character literals are one byte.  sizeof('c') == 1 @@ -238,7 +239,10 @@ string& fooRef = foo; // This creates a reference to foo.  fooRef += ". Hi!"; // Modifies foo through the reference  cout << fooRef; // Prints "I am foo. Hi!" -fooRef = bar; // Error: references cannot be reassigned. +// Doesn't reassign "fooRef". This is the same as "foo = bar", and +//   foo == "I am bar" +// after this line. +fooRef = bar;  const string& barRef = bar; // Create a const reference to bar.  // Like C, const values (and pointers and references) cannot be modified. @@ -284,7 +288,7 @@ public:      // Functions can also be defined inside the class body.      // Functions defined as such are automatically inlined. -    void bark() const { std::cout << name << " barks!\n" } +    void bark() const { std::cout << name << " barks!\n"; }      // Along with constructors, C++ provides destructors.      // These are called when an object is deleted or falls out of scope. @@ -296,7 +300,7 @@ public:  }; // A semicolon must follow the class definition.  // Class member functions are usually implemented in .cpp files. -void Dog::Dog() +Dog::Dog()  {      std::cout << "A dog has been constructed\n";  } @@ -319,7 +323,7 @@ void Dog::print() const      std::cout << "Dog is " << name << " and weighs " << weight << "kg\n";  } -void Dog::~Dog() +Dog::~Dog()  {      cout << "Goodbye " << name << "\n";  } @@ -328,7 +332,7 @@ int main() {      Dog myDog; // prints "A dog has been constructed"      myDog.setName("Barkley");      myDog.setWeight(10); -    myDog.printDog(); // prints "Dog is Barkley and weighs 10 kg" +    myDog.print(); // prints "Dog is Barkley and weighs 10 kg"      return 0;  } // prints "Goodbye Barkley" @@ -337,7 +341,7 @@ int main() {  // This class inherits everything public and protected from the Dog class  class OwnedDog : public Dog { -    void setOwner(const std::string& dogsOwner) +    void setOwner(const std::string& dogsOwner);      // Override the behavior of the print function for all OwnedDogs. See      // http://en.wikipedia.org/wiki/Polymorphism_(computer_science)#Subtyping @@ -421,7 +425,7 @@ int main () {      Point up (0,1);      Point right (1,0);      // This calls the Point + operator -    // Point up calls the + (function) with right as its paramater +    // Point up calls the + (function) with right as its parameter      Point result = up + right;      // Prints "Result is upright (1,1)"      cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; @@ -429,6 +433,85 @@ int main () {  }  ///////////////////// +// Templates +///////////////////// + +// Templates in C++ are mostly used for generic programming, though they are +// much more powerful than generics constructs in other languages. It also +// supports explicit and partial specialization, functional-style type classes, +// and also it's Turing-complete. + +// We start with the kind of generic programming you might be familiar with. To +// define a class or function that takes a type parameter: +template<class T> +class Box { +public: +    // In this class, T can be used as any other type. +    void insert(const T&) { ... } +}; + +// During compilation, the compiler actually generates copies of each template +// with parameters substituted, and so the full definition of the class must be +// present at each invocation. This is why you will see template classes defined +// entirely in header files. + +// To instantiate a template class on the stack: +Box<int> intBox; + +// and you can use it as you would expect: +intBox.insert(123); + +// You can, of course, nest templates: +Box<Box<int> > boxOfBox; +boxOfBox.insert(intBox); + +// Up until C++11, you must place a space between the two '>'s, otherwise '>>' +// will be parsed as the right shift operator. + +// You will sometimes see +//   template<typename T> +// instead. The 'class' keyword and 'typename' keyword are _mostly_ +// interchangeable in this case. For full explanation, see +//   http://en.wikipedia.org/wiki/Typename +// (yes, that keyword has its own Wikipedia page). + +// Similarly, a template function: +template<class T> +void barkThreeTimes(const T& input) +{ +    input.bark(); +    input.bark(); +    input.bark(); +} + +// Notice that nothing is specified about the type parameters here. The compiler +// will generate and then type-check every invocation of the template, so the +// above function works with any type 'T' that has a const 'bark' method! + +Dog fluffy; +fluffy.setName("Fluffy") +barkThreeTimes(fluffy); // Prints "Fluffy barks" three times. + +// Template parameters don't have to be classes: +template<int Y> +void printMessage() { +  cout << "Learn C++ in " << Y << " minutes!" << endl; +} + +// And you can explicitly specialize templates for more efficient code. Of +// course, most real-world uses of specialization are not as trivial as this. +// Note that you still need to declare the function (or class) as a template +// even if you explicitly specified all parameters. +template<> +void printMessage<10>() { +  cout << "Learn C++ faster in only 10 minutes!" << endl; +} + +printMessage<20>();  // Prints "Learn C++ in 20 minutes!" +printMessage<10>();  // Prints "Learn C++ faster in only 10 minutes!" + + +/////////////////////  // Exception Handling  ///////////////////// @@ -436,12 +519,13 @@ int main () {  // (see http://en.cppreference.com/w/cpp/error/exception)  // but any type can be thrown an as exception  #include <exception> +#include <stdexcept>  // All exceptions thrown inside the _try_ block can be caught by subsequent  // _catch_ handlers.  try {      // Do not allocate exceptions on the heap using _new_. -    throw std::exception("A problem occurred"); +    throw std::runtime_error("A problem occurred");  }  // Catch exceptions by const reference if they are objects  catch (const std::exception& ex) @@ -489,7 +573,7 @@ bool doSomethingWithAFile(const char* filename)  {      FILE* fh = fopen(filename, "r"); // Open the file in read mode      if (fh == nullptr) // The returned pointer is null on failure. -        reuturn false; // Report that failure to the caller. +        return false; // Report that failure to the caller.      // Assume each function returns false if it failed      if (!doSomethingWithTheFile(fh)) { @@ -510,7 +594,7 @@ bool doSomethingWithAFile(const char* filename)  {      FILE* fh = fopen(filename, "r");      if (fh == nullptr) -        reuturn false; +        return false;      if (!doSomethingWithTheFile(fh))          goto failure; @@ -532,7 +616,7 @@ void doSomethingWithAFile(const char* filename)  {      FILE* fh = fopen(filename, "r"); // Open the file in read mode      if (fh == nullptr) -        throw std::exception("Could not open the file."); +        throw std::runtime_error("Could not open the file.");      try {          doSomethingWithTheFile(fh); @@ -550,7 +634,7 @@ void doSomethingWithAFile(const char* filename)  // Compare this to the use of C++'s file stream class (fstream)  // fstream uses its destructor to close the file.  // Recall from above that destructors are automatically called -// whenver an object falls out of scope. +// whenever an object falls out of scope.  void doSomethingWithAFile(const std::string& filename)  {      // ifstream is short for input file stream @@ -581,8 +665,56 @@ void doSomethingWithAFile(const std::string& filename)  //   vector (i.e. self-resizing array), hash maps, and so on  //   all automatically destroy their contents when they fall out of scope.  // - Mutexes using lock_guard and unique_lock + + +///////////////////// +// Fun stuff +///////////////////// + +// Aspects of C++ that may be surprising to newcomers (and even some veterans). +// This section is, unfortunately, wildly incomplete; C++ is one of the easiest +// languages with which to shoot yourself in the foot. + +// You can override private methods! +class Foo { +  virtual void bar(); +}; +class FooSub : public Foo { +  virtual void bar();  // overrides Foo::bar! +}; + + +// 0 == false == NULL (most of the time)! +bool* pt = new bool; +*pt = 0;  // Sets the value points by 'pt' to false. +pt = 0;  // Sets 'pt' to the null pointer. Both lines compile without warnings. + +// nullptr is supposed to fix some of that issue: +int* pt2 = new int; +*pt2 = nullptr;  // Doesn't compile +pt2 = nullptr;  // Sets pt2 to null. + +// But somehow 'bool' type is an exception (this is to make `if (ptr)` compile). +*pt = nullptr;  // This still compiles, even though '*pt' is a bool! + + +// '=' != '=' != '='! +// Calls Foo::Foo(const Foo&) or some variant copy constructor. +Foo f2; +Foo f1 = f2; + +// Calls Foo::Foo(const Foo&) or variant, but only copies the 'Foo' part of +// 'fooSub'. Any extra members of 'fooSub' are discarded. This sometimes +// horrifying behavior is called "object slicing." +FooSub fooSub; +Foo f1 = fooSub; + +// Calls Foo::operator=(Foo&) or variant. +Foo f1; +f1 = f2; +  ``` -Futher Reading: +Further Reading:  An up-to-date language reference can be found at  <http://cppreference.com/w/cpp> | 
