diff options
Diffstat (limited to 'c++.html.markdown')
-rw-r--r-- | c++.html.markdown | 155 |
1 files changed, 142 insertions, 13 deletions
diff --git a/c++.html.markdown b/c++.html.markdown index 67fa054c..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 @@ -287,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. @@ -299,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"; } @@ -322,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"; } @@ -331,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" @@ -340,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 @@ -424,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"; @@ -432,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 ///////////////////// @@ -439,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) @@ -535,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); @@ -553,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 @@ -584,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> |