Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Hands-On Design Patterns with C++

You're reading from   Hands-On Design Patterns with C++ Solve common C++ problems with modern design patterns and build robust applications

Arrow left icon
Product type Paperback
Published in Jan 2019
Publisher Packt
ISBN-13 9781788832564
Length 512 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Fedor G. Pikus Fedor G. Pikus
Author Profile Icon Fedor G. Pikus
Fedor G. Pikus
Arrow right icon
View More author details
Toc

Table of Contents (21) Chapters Close

Preface 1. An Introduction to Inheritance and Polymorphism FREE CHAPTER 2. Class and Function Templates 3. Memory Ownership 4. Swap - From Simple to Subtle 5. A Comprehensive Look at RAII 6. Understanding Type Erasure 7. SFINAE and Overload Resolution Management 8. The Curiously Recurring Template Pattern 9. Named Arguments and Method Chaining 10. Local Buffer Optimization 11. ScopeGuard 12. Friend Factory 13. Virtual Constructors and Factories 14. The Template Method Pattern and the Non-Virtual Idiom 15. Singleton - A Classic OOP Pattern 16. Policy-Based Design 17. Adapters and Decorators 18. The Visitor Pattern and Multiple Dispatch 19. Assessments 20. Other Books You May Enjoy

Classes and objects

Object-oriented programming is a way to structure a program by combining the algorithms and the data that the algorithms operate on into single entities called objects. Most object-oriented languages, including C++, are class-based. A class is a definition of an object—it describes the algorithms and the data, its format, and relations to other classes. An object is a concrete instantiation of a class, that is, a variable. An object has an address, which is a location in memory. A class is a user-defined type. In general, any number of objects can be instantiated from the definition provided by the class (some classes limit the number of objects that can be created, but this is an exception, not the norm).

In C++, the data contained in a class is organized as a collection of data members, variables of different types. The algorithms are implemented as functions—the methods of the class. While there's no language requirement that the data members of a class should be somehow relevant to the implementation of its methods, it's one of the signs of good design when the data is well encapsulated in the classes, and the methods have limited interaction with external data.

This concept of encapsulation is central to the classes in C++—the language allows us to control which data members and methods are public—visible outside of the class, and which are internal—private to the class. A well-designed class has mostly, or only, private data members, and the only public methods are those needed to express the public interface of the class—in other words, what the class does. This public interface is like a contract—the class designer promises that this class provides certain features and operations. The private data and methods of the class are part of the implementation, and they can be changed as long as the public interface, the contract we've committed to, remains valid. For example, the following class represents a rational number and supports the increment operation, as exposed by its public interface:

class Rational {
public:
Rational& operator+=(const Rational& rhs);
};

A well-designed class doesn't expose any more of the implementation details than it has to through its public interface. The implementation isn't part of the contract, although the documented interface may impose some restrictions on it. For example, if we promise that all rational numbers don't contain any common multipliers in the numerator and denomination, the addition should include the step of canceling them. That would be a good use of a private member function—the implementation of several other operations will need to call it, but the client of the class never needs to call it because every rational number is already reduced to its lowest terms before it's exposed to the callers:

class Rational {
public:
Rational& operator+=(const Rational& rhs);
private:
long n_; // numerator
long d_; // denominator
void reduce();
};
Rational& Rational::operator+=(const Rational& rhs) {
n_ = n_*rhs.d_ + rhs.n_*d_;
d_ = d_*rhs.d_;
reduce();
return *this;
}
Rational a, b;
a += b;

The class methods have special access to the data members—they can access the private data of the class. Note the distinction between the class and the object here—operator+=() is a method of the Rational class and is invoked on the object, a. However, it has access to the private data of the b object as well, because a and b are objects of the same class. If a member function references a class member by name without any additional qualifiers, then it's accessing a member of the same class it's invoked on (we can make it explicit by writing this->n_ and this->d_). Accessing members of another object of the same class requires a pointer or a reference to that object, but is otherwise not restricted, as would have been the case if we tried to access a private data member from a non-member function.

By the way, C++ also supports C-style structs. But in C++, a struct isn't limited to just an aggregate of data members—it can have methods, public and private access modifiers, and anything else classes have. From a language point of view, the only difference between a class and a struct is the default access—in a class, all members and methods are private by default, while in a struct they're public. Beyond that, the use of structs instead of classes in a matter of convention—traditionally, structs are used for C-style structs (structs that would be legal in C) as well as almost C-style structs, for example, a struct with only a constructor added. Of course, this boundary isn't precise and is a matter of coding styles and practices in each project or team.

In addition to the methods and data members we've seen, C++ also supports static data and methods. A static method is very similar to a regular non-member function—it isn't invoked on any particular object, and the only way it can get access to an object of any type is through its arguments. However, unlike a non-member function, a static method retains its privileged access to the private data of the class.

Classes by themselves are a useful way to group together the algorithms and the data they operate on and to limit access to some data. However, the most powerful object-oriented features of C++ are inheritance and the resulting class hierarchies.

You have been reading a chapter from
Hands-On Design Patterns with C++
Published in: Jan 2019
Publisher: Packt
ISBN-13: 9781788832564
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime