MYF

[RA] Ch14 Transition to C++

Reading Assignment: All of Programming Chapter 14 Transition to C++

Object Oriented Programming

One core difference between C and C++ is that C++ supports object oriented programming. in OOP, we think about our program in terms of objects which have state inside of them, and ask the objects to perform actions.

Two of the primary concepts in OOP are classes and objects. Technically, the only difference in C++ between a class and a struct is the default access control of its members. Objects are instances of classes, that is, when you draw a box for something of a class type, you have made an object.

In C++, classes can have functions declared inside of them, which are key to the OO nature. These functions are either called member functions or methods. While methods can be declared inside of structs or classes in C++, many programmers adhere to the convention of using structs for types that only contains data, and classes for types that have methods.

Access Control

In C++, there are three kinds of access control that every member can have: public, private, protected. In a struct, the default access is public, while in a class, the default access is private.

  • public: It can be accessed by any piece of code.
  • private: It can only be accessed by code within that classes.
  • protected: To be discussed in Chapter 18.

BankAccount example is given here.

Encapsulation: Method Acts on Objects

Class encapsulate-combine into a single logical unit-the data and methods that act on them. That is, we can think of these methods as being inside each instance of the object. Calling them causes them to act on the data inside that particular instance of the object.

While the “code inside the object” approach works logically, it would be quite inefficient to implement-and to execute by hand. Instead, C++ add and extra parameter to each method, called this, which is a pointer to the object that the method is insider.

Const Methods

There are times when we want to specify that the implicit this argument is a const pointer. That is, that the compiler should consider it to be a const T * const this rather than just T * const this. As we do not explicitly declare this ourselves, C++ provides a special place to put the const: after the close parenthesis of the parameter list, but before the open curly brace of the function body.

When we should not do any modification to current object, we are supposed to add a const after declaration.

Plain Old Data

C++ makes a distinction between classes that are plain old data(POD) classes, and classes which are not. At a high level, all POD types have direct C analogs-they are just sequences of fields in memory.

Discussing exactly what makes a class non-POD is quite complex, varies between C++03 and C++11. The simplest rule is that if you can write it in C, it is a POD class.

Static Members

There are times that we want all instances of a class to share the same box for a particular field, or to have a method that acts on no particular instance of that class. Static means that there is one “box” shared by all instances of a class, not one box per instance.

1
2
3
4
5
6
class BankAccount {
private:
static int nextAccountNumber;
}

int BankAccount::nextAccountNumber = 0;

The last line of code actually creates the box, and must be placed at the global scope-outside of any functions or classes. The name of the variable, BankAccount::nextAccountNumber specifies the nextAccountNumber “inside of” the BankAccount class. The :: is scope resolution operator, which allows us to specify a name inside of another named scope, such as a class.

You can also write static methods in a class. These methods cannot access non-static members of the class, because unlike non-static methods, they do not have a this pointer passed to them-they operate on no particular object.

Classes Can Contain Other Types

In C++, classes can contain other types inside of them. Such a declaration can either be a typedef of an existing type, or even the declaration of an entire other classes.

1
2
3
4
5
6
7
8
9
10
11
12
class BankAccount{
public:
typedef double money_t;
private:
class Transaction{
public:
money_t amount;
timeval when;
}
money_t balance;
Transaction *transactions;
}

Line 3 makes money_t a typedef for double. This type declaration is public, so it can be referenced freely outside of the class, however, since the name is inside of the class, the scope resolution operator mush be used-the type name would be written BankAccount::money_t. Inside the class, it can be referenced simply as money_t.

This example also declares an inner class Transaction, which is private. Code outside of BankAccount class cannot make use of this type at all. The Transaction class has its own fields with their own visibility.

If you have a private inner class with public members. Having a private class prevents code outside of the class from naming the type, that is, it can not make use of the type name BankAccount::Transaction. Such a restriction typically means that we design our code such that the private inner class never “escape” the outer class, that is, we never return instances of the class to the code in the outside world, and have no public fields whose type is the inner class. If we do not let instances of this private class escape, then there is nothing complex to thinking about how the access restrictions work: code in the outer class can access members of the inner class according to their visibility modifiers, and code outside of the outer class cannot even “see” the inner class at all. If we do allow the inner class to escape the outer class, then even though that code cannot name the type, it can still access public fields in the object.

The Basics of Good OO Design

Classes are nones. Methods are verbs.

Keep classes small and do their purpose.

Be as general as you can be, but no more.

Avoid “Manager” classes.

References

A reference is similar to a pointer in that it provides access to a box through a level of indirection, however, there are many differences between references and pointers. A reference is intended to conceptually be “another name for a box”.

1
int & x = y;

It is conceptually another name for y‘s box.

There are several differences:

  • Once a reference is initialized, a reference can not be changed to refer to a different box. By contrast, pointers can have what they point at changed anytime.
  • References are automatically dereferenced, whereas pointers must be explicitly dereferenced.
  • A reference must be initialized when it is declared.
  • We can not have NULL references.
  • We can not have a reference to a reference or a pointer to a reference. However, we can have a reference to a pointer
  • We cannot perform reference arithmetic.

We can translate reference-based code to pointer-based code according to the following rules:

  • Declaration
  • Initialization
  • Uses

Namespaces

C++ introduces a way to create named scopes, called namespaces, which can be used from anywhere in the program. Declaration can be placed inside of a namespace by wrapping namespace somename {...} around the declarations. For example:

1
2
3
4
5
namespace dataAnalysis{
class DataPoint{...};
class DataSet {...};
DataSet combineDataSet(DataSet *array, int n);
}

There are two ways to reference a name declared inside of a namespace. The first is to use the scope resolution operator ::. The second way to reference names insider of a namespace is to open namespace with using keyword. We can also use using to bring particular items from a namespace into the current scope. For example, we can write using std::vector to bring only the name vector from the std namespace into scope.

Opening namespaces is generally regarded as something to be done sparingly, and possibly avoided entirely in large scopes. Therefore, using std::vector instead of just using namespace std is preferable.

Function Overloading

The concept of allowing multiple functions of the same name is called function overloading. Note that an overloading is legal if the functions can be distinguished by their parameter types, read as an ordered list.

If you are going to use function overloading, you should follow a few simple guidelines. First, you should only overload functions when they perform the same task, but on different types. For example, our max functions that we described earlier do the same computation, but one different types. Second, you should only overload functions in such a way that understanding what the best choice is for a particular call is straightforward.

Name Mangling

The C++ compiler must ensure that the names of the symbols that the linker sees are unique. To accomplish this goal, the C++ compiler performs name mangling-adjusting the function names to encode the parameter type information, as well as what class and namespace the function resides inside of-so that each name is unique.

Operator Overloading

C++ takes function overloading one step further, allowing operator overloading.

1
2
3
4
5
6
7
8
9
10
11
12
class Point {
private:
int x;
int y;
public:
point operator+(const Point &rhs)const{
Point ans;
ans.x = x + rhs.x;
ans.y = y + rhs.y;
return ans;
}
}

Other Aspects of Switching to C++

Compilation

C++ programs are compiled with g++. For everything we are going to do in this book, -std=gnu++98 will work fine, which is also a default standard. If you want to use new features in C++11, you should specify -std=gnu++11. For C++11 features, consult the documentation page:

https://gcc.gnu.org/projects/cxx-status.html#cxx11

The bool Type

C++ has an actual bool type, with values true and false.

Void Pointers

C++ removes the flexibility of assigning any pointer type to a void pointer and a void pointer to any pointer type without a cast. In chapter 15, C++ provides a new mechanism for dynamic allocation which returns a correctly typed pointer, instead of a void *. Being able to write classes which can hold any type using templates is one of the compelling reasons to switch to C++ before learning about data structures in Part III.

Standard Headers

#include<sdtio.h> => #include<cstdio>

Code Organization

In C++, classes declarations typically occur in header files. It is generally considered to be fine to write the implementation of very short method directly inside of the class declaration in the header file. For the remaining methods, which need their implementation written in the .cpp file. However, when we write these methods, we must specify which class they belong in. We do so with the scope resolution operator to give the fully qualified name in the declaration.

Default Values

C++ allows default values to be specified for some or all of the parameters of a function. These default values provide the caller of the function in question with the ability to omit the arguments for certain parameters if the default values are desired.

1
int f(int x, int y = 3, int z = 4, bool b = false);

Reference Material

http://www.cplusplus.com