This article lists the features C++ adds to C, from an ex-C programmer’s point of view. A couple of months ago I wrote part 1, which detailed the non-OO features. This second part details the object-oriented features, though I haven’t given them exactly watertight separation.

Again, this is a quick reference, and the idea is to follow the links to further information if you want to know more about any of them.

So, part 2 of 2, the OO features.

Class and (de)constructors

Virtual functions

One of the most important constructs in OO C++, a virtual function, is a method which can be overridden by a subclass. If you have a Cat class with a virtual void make_noise() method, then your subclasses HouseCat and Lion can override that with meowing and roaring behaviour. If you have a list of Cat s and want them all to make noise, you simply loop through the list and call make_noise() on each one (the virtual function table takes care of the details). Note that in languages like Python, all functions act virtual.

class with a method, then your subclasses and can override that with meowing and roaring behaviour. If you have a list of s and want them all to make noise, you simply loop through the list and call on each one (the virtual function table takes care of the details). Note that in languages like Python, all functions act virtual. A pure virtual function is a virtual function in your parent class that must be overridden in the base class — all cats make noise. The class with the pure virtual function is called “abstract”, and you can’t instantiate it directly. A class with only pure virtual functions defines an interface or API. The weirdest thing about pure virtual functions are their weird =0 syntax: you define them like so: virtual void make_noise() = 0;

syntax: you define them like so: You should define your destructor as virtual when your class has one or more virtual functions. If you don’t, and you delete an object through a base class pointer, the subclass’s destructor won’t get called — memory leak. Stroustrup has an example (albeit contrived) of how this works.

Inheritance and friends

Classes can have public , private , and protected sections. Private variables and methods are only accessible by the class’s own members, not even its subclasses — useful for implementation details you don’t want to expose as part of the class’s API. Protected members are accessible by subclasses, but not anyone else. And public members are accessible by everyone.

, , and sections. Private variables and methods are only accessible by the class’s own members, not even its subclasses — useful for implementation details you don’t want to expose as part of the class’s API. Protected members are accessible by subclasses, but not anyone else. And public members are accessible by everyone. However, if B is defined as a friend class or friend member inside class A, B can access A’s private parts (yes, it should probably be called married_to ). The C++ FAQ Lite has a good section on friend ship.

). The C++ FAQ Lite has a good section on ship. Public inheritance is the usual form of “a Lion is a Cat” inheritance ( class Lion : public Cat { ... }; ). I’ve never used private and protected inheritance, and can’t quite figure them out, so I’m leaving that as an exercise for the reader. :-)

). I’ve never used private and protected inheritance, and can’t quite figure them out, so I’m leaving that as an exercise for the reader. :-) Multiple inheritance is when your class inherits from two base classes at once. Don’t get too clever with this! For instance, if Dad pays the bills, you could have class Dad : public Human, public BreadWinner { ... };

Type casting

Right up there with the =0 notation and using bit-shift operators for I/O are the C++ cast operators. You can use regular C casts like i = (int)f; but they’re discouraged. You use static_cast<type>(expression) to cast between numeric types or to cast a pointer down in an inheritance chain (you’ve got to be somewhat careful). Use reinterpret_cast<type>(expression) to cast expression’s bits to type (know what a core dump is first). And use const_cast to cast away the const attribute on something.

notation and using bit-shift operators for I/O are the C++ cast operators. You can use regular C casts like but they’re discouraged. You use to cast between numeric types or to cast a pointer down in an inheritance chain (you’ve got to be somewhat careful). Use to cast expression’s bits to type (know what a core dump is first). And use to cast away the const attribute on something. There’s also dynamic_cast<type>(expression) to cast pointers or references, which is safe but requires compiler run-time overhead. It checks the type of expression at run-time, and if it’s able to be casted to type, all good. If not, dynamic_cast returns NULL (or throws an exception for references).

to cast pointers or references, which is safe but requires compiler run-time overhead. It checks the type of expression at run-time, and if it’s able to be casted to type, all good. If not, returns (or throws an exception for references). More generally, there’s RTTI (Run-Time Type Information): dynamic_cast is part of that, and the other part is the typeid(expression) operator, which returns a type information object about the given expression. Useful for comparing types at run-time, printing type names, etc.

New and delete

To allocate an object on the heap, use Class* pobj = new Class; — this tries to allocate memory (throwing an exception if that fails) and calls Class ’s constructor on the object. You can allocate arrays with new like int* pint = new int[5]; . For super-advanced control over how new allocates, read up on placement new and overloading new.

— this tries to allocate memory (throwing an exception if that fails) and calls ’s constructor on the object. You can allocate arrays with new like . For super-advanced control over how allocates, read up on placement and overloading new. Of course, the opposite of new is delete , which calls the class’s destructor and then frees the memory new allocated. Just like with malloc() and free() , for every new there must be an equal and opposite delete . Hint: use AC/DC (RAII) if you can.

Operator overloading

You can overload pretty much all operators in C++ to work with your own classes. If someone else has done this for you, great (e.g., std::string overloading + to mean concatenation). But mainly because of C++’s memory and exception model, there are many gotchas. Do your homework before getting too clever.

overloading to mean concatenation). But mainly because of C++’s memory and exception model, there are many gotchas. Do your homework before getting too clever. Note that you can’t overload these operators: . ?: :: and the semi-obscure .* operator. Also, you can’t add operators of your own (say ** to mean to-the-power-of).

Templates

It took me a while to grok templates, but they’re simple at heart — just a way to avoid repeating yourself. Instead of writing an IntArray class and then finding you need FloatArray and StringArray later, you can just write a generic Array<T> class which is an Array of class or type T . That’s a class template.

class and then finding you need and later, you can just write a generic class which is an of class or type . That’s a class template. Function templates let you write generic functions instead of classes. So instead of writing min(int x, int y) and min(double x, double y) you can just write a min<T>(T x, T y) . Then you can call min() on whatever number types you want and the compiler will generate the right code for each (yes, all this usually means bigger executables).

and you can just write a . Then you can call on whatever number types you want and the compiler will generate the right code for each (yes, all this usually means bigger executables). Template arguments can have defaults. So you can have say LargeNumber<class T =long> — if you instantiate a plain LargeNumber it’ll use longs, but you can override it to use doubles by saying LargeNumber<double> .

Exceptions

Exception handling in C++, like operator overloading, is a really nice idea that can turn sour pretty quickly if you don’t keep it in the fridge (i.e., handle with care). A number of C++ coding standards simply disallow exceptions, perhaps for good reason. At least make sure you learn the way of the RAII before delving here.

Well, thanks for listening!

10 August 2010 by Ben 5 comments