Basic Stuff

This is stuff that is sure to come up in a typical interview for a C++ software engineering position

Encapsulation

This is the hiding of info by keeping member data, or whatever else is not part of the interface (implementation details), private in your classes. The benefit of this is that you are free to change the implementation without affecting clients (except for causing a recompile, possibly).

C++ Faq Lite on encapsulation

Polymorphism

The ability to manipulate various different objects via a common base class pointer. This is supposed to keep your code generic, methinks, by encouraging you to design an interface for your base class and then implement that interface in the derived classes, and then manipulate those objects using a pointer or reference to the base class.

Inheritance

Commonly thought of as a way to "reuse existing code" by creating a new class that inherits from another existing class. This way you can extend the functionality of an existing class w/o touching the existing class's code. But Herb Sutter has a bit of a different take on the use of inheritance--"Inherit, not to reuse, but to be reused. Don't inherit publicly to reuse code (that exists in the base class); inherit publicly in order to be reused (by existing code that already uses base objects polymorphically)." [C++ Coding Standards, p. 64]. He also says "In correct inheritance, a derived class models a special case of a more general base concept." [ibid, p. 66]

Should model "is-a".

There are also weird things like protected and private inheritance. I have never seen these in use.

C++ Faq Lite on inheritance

Virtual

This is what allows inheritance to work. If you declare a function virtual, you can override that function in a derived class. Then a pointer to a base class can do different stuff (polymorphism).

Make destructors virtual in base classes

This is so that deleting a pointer to a base class which really points to a derived-class object calls the proper chain of destructors. If you don't declare the destructor virtual, the base class destructor is the only that will be called. If you do declare the destructor virtual, then the destructors are chained from most-derived on down to base, which is what you want of course.

Const

As Scott Meyers says, "Use const whenever possible". I agree with this because making something const removes that thing from the giant list of things you have to think about. When you are reading new code and trying to make sense of it, it helps to winnow down the amount of stuff you have to keep in your head all at once.

You can make various things const.

  • data members--just declare them const in the class declaration. You will have to initialize them in the constructor initializer list since a const cannot be changed once it is set. So you can never write x = y; if x is declared const. You can only write const int x = y; This presents a problem for data members, so the only way to initialize a const data member is via the constructor initializer list.

  • pointers--these are tricky because there are two pointer things that can be const--the pointer itself, and the thing the pointer points to. The syntax is different in each case.

    To make the pointer itself const: char* const p = "abc";

    To make the thing pointed to const: const char* p = "abc";

    To make both const: const char* const p = "abc";

  • member functions--make class member functions by adding const after the declaration and definition (it's part of the function signature). A const member function is useful because it tells you "I won't change anything in the class (i.e., I won't change any class member values, i.e., I won't call any non-const member functions)" Or put another way, "I can only be called on const objects". This is known as const correctness. Another way to think of it: in a non-const member function, the this pointer for a class 'C' acts as if it's declared C* const this;, inside a const member function, the this pointer acts like const C* const this;

Mutable

This keyword is used to un-const something, so that it can be changed by a const function. Things get a little sticky here regarding the definition of const for a class. If you feel like you can safely change some internal class member yet the class object still retains some "constness" to the outside world, you need to declare that particular member as mutable. Otherwise, your code won't compile (you can't modify data members in a const function............unless they are mutable!).

C++ Faq Lite on const

What class functions does the compiler write for you?

Default Constructor

The compiler will write this for you only if you have no other constructors declared. The one generated by the compiler does nothing.

Copy Constructor

You'll get one of these only if needed. The compiler-generated version will do bitwise copy. How do you know if a copy constructor is needed? If you pass your class object by value to a function, that will generate a call to the copy constructor. If you initialize from another object, that calls the copy constructor. Eg. C c; C c2(c); // copy constructor called. C c3 = c; // copy constructor called. Sometimes there can be confusion between when a copy constructor and an assignment operator are invoked. If the statement contains the creation of a new object, then the copy constructor is invoked, even when you see an '=', as in the creation of c3 above.

Assignment Operator

You'll get one of these only if needed. The compiler-generated version will do bitwise copy. C c; C c2; c = c2; // assignment operator called.

Other Stuff

C++ will also generate some address-of operators for you. You don't need to know this.

Multiple Inheritance

Everyone recommends avoiding MI, so follow that advice. You can get into messy situations, such as the object having multiple versions of the same base object, etc. I get a headache even thinking about most of it. Not worth it.

Constructor Initializer List

This is the thing after the colon before a constructor body. As in MyClass::MyClass(int x) : c(x) { ... } The constructor initializer list is the only way to initialize reference members and consts. It is also the only way to pass parameters to constructors of sub objects (either base classes or member objects). It's also good to use it to invoke member copy constructors to avoid default construction of those objects followed by assignment, although maybe compilers nowadays optimize this away anyhow.

Abstract Base Class ("ABC")

What is it?

It's an interface definition. It's a class that you cannot instantiate. Its purpose is to serve as the base class for other classes you will derive from it, and it defines a common interface (set of class methods) that all instances must implement.

How do you create one?

You indicate that a class is an ABC by setting one or more of its functions "= 0", which turns that function into a "pure virtual function". This is kind of a hackish syntax. Example: class ABC { ... virtual function() = 0; ... };

Only one function in a class needs to be declared pure virtual to make the class abstract.

You may be asked in an interview whether you can define a function body for a pure virtual function. The answer is yes. Just as in a regular base class, you can define common functionality in an ABC, even in functions marked as pure virtual. There seems to be common confusion with respect to this. The only thing you can't do with an ABC is instantiate objects of the class.

C++ Faq Lite on abstract base classes

Big O Notation

This is a way to indicate the relationship between the time an operation will take and the number of items being operated on (dataset size).

These are some you should be familiar with, methinks.

O(1)

Constant time. Time to do the computation does not depend at all on the number of items being operated on.

O(n)

This means "linear time", aka "the time the operation will take is directly proportional to the number of items being operated on". An example is a search through an unsorted list. The only way to do it is look through the list item by item.

O(n-squared)

This means whatever you are doing will take a long time--not good.

O(log(n))

Just mumble something about "binary trees" and you'll be fine.