C++ is not an easy language to master. Many people are able to land C++ jobs without being a C++ guru. However, the more you know, the better your chances of landing that job and being happy in it. If you’ve learned the basics of C++, you’ll want to take it up to the next level. Here’s how.
We covered some C++ basics in an earlier article. One commenter to that piece mentioned copy constructors, which is an excellent place to start for a more intermediate examination of the language, because it requires you to understand several aspects of C++: How constructors work, how to overload your constructors, how to overload operators, and the definition of a deep copy versus a shallow copy.
Once you’ve reviewed copy constructors, we can move on to some other important elements: (As with our beginner’s piece, this is just a sprinkling of topics to give you an idea of the level; it’s not an exhaustive list. Therefore, don’t just learn these topics and call it good; instead, study as much as you can, and when you reach a point where your knowledge includes these topics, you’re probably in good shape.)
Although operating systems will clean up leftover memory after a program ends, many programs (such as Web servers) run indefinitely. And that’s a problem, because an unstopped program will grow and grow in memory size until the system crashes.
There’s a simplistic answer to the memory-leak conundrum: “For every new make sure you have a delete.” But in fact, things are a bit more complex.
Think about copy constructors. Let’s suppose you copy an object, and then delete the first object. If the second object contains a pointer to an inner object inside the first object, then deleting the first object can be dangerous to the program’s stability.
If you have an object that contains a pointer to some other object, and you delete that first object, you need to determine whether you should delete the second object, as well; that second object might be referred to by yet a third object, in which case you probably wouldn’t want to delete the second object. That’s the sort of logical thinking you need to employ in order to keep your memory in check.
If you’re building a system with such complexity, you may want to use a library that includes reference counts, and possibly even one that does automatic deletion. Even in a simple program, you might find those libraries helpful: Suppose you construct an object that’s used by a function within a library you’re using; do you know for sure if that function is going to delete the object for you when it’s finished, or if you need to? In either case, trouble can occur if you’re not careful.
You’ll want to understand when and how to use pure virtual functions in order to create interfaces, and how to use interfaces to accomplish polymorphism. If you understand this, then you’re in good shape for understanding how to accomplish object-oriented programming in C++.
Casting in C++
Know when to use simple C-style casting, when to use static_cast, dynamic_cast, const_cast, and reinterpret_cast, and how to avoid crashes from casting incorrectly. For example, C-style casting lets you cast between objects that aren’t a match, potentially resulting in a crash:
A *a = new A();
B *b = (B *)a;
If A and B aren’t related through a hierarchy, this is a bad idea; yet the compiler will do it anyway, and you could easily end up with a crash. But if you use static_cast, the compiler will issue an error if a cast isn’t possible:
B *b = static_cast<B *>(a);
cast.cpp:23:27: error: invalid static_cast from type ‘A *’ to type ‘B*’
B *b = static_cast<B *>(a);
Make sure you understand how to avoid casts altogether. In some cases they might be necessary. But in a lot of cases, if it seems like you need them, then you might have a problem in your class design.
C++11 added lambda functions. Using the Boost library, you could accomplish lambda functions with earlier versions of C++, but learn the new C++11 way. Although lambda functions are nothing new in the programming world, they have become especially important in the past decade as people find new ways to solve problems. At the same time, know how to write code that accomplishes the same thing without lambda functions.
Learn how to do it safely.
Templates are the wrenches and screwdrivers of C++, yet beginners often have a hard time wrapping their minds around them. They don’t need to be that difficult. Make sure you understand:
- How to derive a non-template class from a template class
- How to derive a template class from another template class
- How to derive a template class from a non-template class
You should understand the implications of all of the above in terms of how and especially when template types are created. Here’s one way to think of templates: You’re creating a new type at compile time. If you’re coming from the C# world, this is technically different from C#’s generics, in which types are created at runtime.
Integrating Your Code With Other People’s Code
If you’re developing some classes, you need to know how to create a header file that other developers can use. Can the other developer actually use your class, based on the class and function declarations in the .h file, without having to pick apart your implementation in the source file? Are you keeping the source in the source file rather than the header, so that it doesn’t get recompiled with every pass through the header? Do you know how to limit a header file to be processed only a single time?
You should also know how to create a class that’s truly reusable, and whether you really need to make a class reusable. In addition, get to know the following concepts:
- When to design a class that should be instantiated, versus a class that should be inherited.
- Whether to make your functions private and protected; for example, do you have a member function that you keep private that could be useful to other programmers? Are you using public member variables that other developers could set when you should be making them private, and using a member function that performs various actions when the variable needs to be set?
- If you’re building classes meant to be inherited, do you know when and why to make members private versus protected, and how to limit frustrations the programmers might encounter if the members are private?
- You should know how to compile your code to both a static-linked library and a dynamic-linked library, and how to make it available to other developers as a header file and library.
Although not technically part of the language itself, make sure you know your compiler options, both within the IDE (if you’re using one) and at the command line prompt. You don’t want to use IDEs as a crutch and be unable to compile at the command line if you’re under a crunch and need to compile your code on a system where you only have a shell login.
Modern Systems Require Modern Programming Styles
Today’s systems are much more sophisticated than they were just ten years ago. We’re doing a lot more code that scales and code that’s parallel. In the world of Web software, asynchronous libraries are often used, which can open up a can of memory management worms. You might provide a callback function that gets called much later, such as after a response from a network connection. You need to know exactly when to clean up any objects created for use in that callback function.
Depending on your industry, you may need to know how to read and write XML, or read and write JSON. Both XML and JSON present particular challenges in C++, as you need to decide whether you’re going to scan the XML or JSON and process each member as you get to it, or first convert the XML or JSON into C++ objects.
Potential employers will likely want to hear about unit testing. In larger software shops, there’s often a testing or quality assurance group that runs large tests on the software. But you, as a programmer, need to know how to perform unit tests on the part of the code you’ve developed.
Additionally, you need to know the tools:
- How to use the debugger proficiently
- How to use source code control
- How to use make and other build tools. Yes, even if you’re using Visual Studio which provides its own build system, you should still know how to use the build tools for times you need to use a library that came with a make file instead of a project file.
C++ is not easy. It takes a long time to master. Keep coding, and keep studying other people’s code. If you don’t yet have 10 years of experience, don’t assume you’ve reached the point of mastery; but with dedication, you’ll advance to the next level.