Basic of C++: A tour

It is very interesting for a language book to have a quick tour before everything. Actually, it is a great idea for people whose first language is not C++. People just don’t have to go through the basic things like control flows to know a language.

Generally, I have a feeling that C++’s code explain more itself. Programmers know more about what they are doing instead of checking documents for reference.

The Basics

Chapter 2 covers the very basic things (that would include control flows). First thing to note is that the introducing of namespace. Namespace in C++ seems to be clear and straightforward. What is not-so-straightforward is the name of header file/shared object library. Well, Java’s package infrastructure makes things more clear, though trying to put everything inside its structure probably is not so clever.

I didn’t expect C++ provides things like ‘auto’. (Well, not the ‘auto’ when I first use C language a few years ago.) Anyway, C++ is not a dynamic tool language. However, if you think about it, it is nothing runtime here, and you just need a compile time check. To be a real dynamic language, the thing you need is a flexible variable type (which is implemented in runtime even if you could do it in compile time) and generic programming for functions.

We finally have bools in C++!

C already have const. It was a beautiful promise that one should keep. constexpr does more than that. It calculates the value at compile time. When using constexpr as decorator of a function, it will evaluate at compile time when possible. Those function must be as simple as only having a return statement. Note that if a value is const, the compiler will assume you to keep the promise. Conclusion: Do keep your promise or you will have something unexpected.

Structs are improved. Say goodbye to the strange typedef!

Operators are functions, which they should be! Just need to have it in mind that if the value is lvalue or rvalue, to make the return type reference when necessary.

We also got a good syntax sugar for initiating fields. And a real enum class which is more than int.

C++ provides a more standard way for error handling. Exception introduced just like all of the other modern programming languages. Static assertions provide error handling on compile time.

There are some designing ideas. Invariant are restrictions applied to class definitions, and should be present in the code. If not, the functions should be independent rather than a member.

Abstract mechanism

As we can find in any articles about OOP, there is some mechanism in classes, like concrete/abstract class and class. There are some concerns under data storage since in C family you have to care more about memory, like the idea of the container. Also, note the following format for heap allocated arrays.

double *elem = new double[s];
delete[] elem;

Instead of making all functions virtual, we need to explicitly specify if a function is a virtual one. A class with at least a virtual function is called abstract class, which can not be instantiated. The mechanism behind overriding is vtbl. Usually, this is to add a 4 byte for pointer at the beginning of each object. If we want to call the virtual function in the base class, we can use scope resolution (::) operator to specify the class name, and this is called suppressed.

Constructor and destructor are called in a certain order. We don’t need to do anything for the constructor. However, for destructors, we need to make them virtual on base classes. Otherwise, only one of them is called.

An important designing idea for C++ is cautious against pointers. In C code, it is not strange for a function to return a raw pointer which points to something in heap. However, it is no longer recommended in C++. Destructors help us manage heap memory more freely. Moreover, we have unique_ptr as a smart pointer.

We need to note that “this” is a pointer, as it is in Java. Also, a const method is one that doesn’t change the object. Moreover, we can specify access-specifier when inheriting.

Copy and move. The default behavior of C++ copy is shallow copy since it just does a copy bitwise. To make it copy deeply, we just need to override operator =. Moreover, C++ provides the std::move mechanism.

std::move is a fast way to generate “right value reference”. In many cases, we don’t really need to copy the whole objects, especially when it is a container( such that copy is expensive. )  && is the mark for right value reference. When it is a parameter of a function, it (instead of the const &) can match the right value reference, to do a memory-economic behavior in the function.

If we don’t want certain behavior in the derived class, we can use the “=delete” mechanism.

class Shape{
public:
    //no copy
    Shape(const Shape&)=delete;
    Shape& operator=(const Shape&)=delete;

    //no move
    Shape(Shape &&)=delete;
    Shape& operator=(Shape &&)=delete;

}

Template. Generic programming is very useful for OOP. C++ has the template grammar:

Single:

template<typename T>

Multiple:

template<typename T, typename U>

Variadic:

template<typename T, typename... Tail>
void f(T head, Tail... tail){
   g(head);
   f(tail...);
}

To override the operator(), we can use it as a functional object. For instance

<typename T> class Less_than{ const T val; public: Less_than(const T &v): val(v){} bool operator()(const T &v) const {return v<val;} } read more

TIJ chapter 8: Polymorphism

Polymorphism(also called dynamic binding or late binding or run-time binding) is an essential concept in OOP. This chapter is basically a more detailed explanation of polymorphism, which is highly relevant to inheritance. (As mentioned in chapter 7, in many cases inheritance is meaningless when polymorphism is not necessary.)

Binding method

How Java find a corresponding method for an object? Unlike languages like C, which use early binding for each function, Java only does early binding for methods with modifiers like static or final. Java has runtime binding for other methods. That’s the reason why people declare methods “final” in the early versions of Java to improve performance.

Runtime binding helps the compiler to refer to an override method to the correct derived class, even if we only know a base-class reference to an object. We can construct special cases where even programmer doesn’t know what kind of derived class an object belongs to, but finally, the compiler will figure out it during the runtime. During runtime, the compiler binds correct binary.

Dynamic dispatch is a fundamental feature of OOP. Java does this for each method, while C++ only enable it for virtual functions.

Extensibility

In this way, the behavior won’t change even if we add new methods for based classes and derived classes, or we add a new derived class. OOP provides extensibility to programming.

Pitfalls

For private methods in a base class, even if you have a public method with the same signature in a derived class, you will call the private one in the base class for a base class reference. It won’t throw an exception, so this should be noticed.

Another thing to note is dynamic binding is only for methods, not field. But if we set each field private and use getters and setters, this shouldn’t be a problem.

Constructor, Destructor, and Polymorphism

The constructor is a static method. When the constructor is called, the calling order is from base to derived. If we have to build a destructor, we will make it reverse, from derived to base.

How about calling overload method in the constructor of the base class?

When the constructor of the base class, method successfully refer to the derived one. However, the derived-related field has not been initialized. So the value printed is neither 1 nor 5. In fact, it is 0.

Memory space is initialized to 0 for objects, and that’s why we get 0 as output. To avoid this, the programmer should think twice before she/he call a method in a constructor. Only final methods (include private ones) are safe to be called in the constructor.

Downcasting

Sometimes we need to downcast an object to call methods only in derived class. Java will check if the downcasting is safe. If not, it will throw a ClassCastException.

 

 

 

TIJ chapter 7: Reusing Classess

Composition, inheritance and delegation are 3 main methods to reuse classes.

Delegation is not a familiar concept for me, and it is not directly supported. However, I think I have used its content before. It just put a member object in the new class and expose all method to the new one.

About inheritance, it always calls the super() constructor even if you don’t called it literally in derived class. As a result, if the base class don’t have a constructor without any parameters, and you don’t call base class constructor literally in derived class, you will get a compile time error.

Upcasting is brought by inheritance. Basically, it means a reference of base class can refer to an instance of derived class. Making good use of this feature help DRY. In some cases, whether using inheritance depends on if upcasting is necessary.

About Final

“Final” usually means “unchangeable”.

If a data is final, then it can either initialize in compile time or run time, and cannot be changed since then. If it is static and final, it has only one piece of storage that cannot be changed.

For non-static final, it can be left blank when declaration, but then must be decided in constructor. In conclusion, a final field must be assigned either with an expression at definition of the field or in every constructor. Of course, if it is static, assignment in constructor is also impossible.

If a reference is final, then it cannot refer to another Object. The object itself can also be changed. You cannot make object unchangeable by using final.

If a parameter of a method is final, it cannot be changed in method. It is usually used to transfer data to anonymous inner class.

Making a method final is to prevent derived class change it. Historically, it may also improve the efficiency, but now this purpose is less useful.

As a result, a private method implies final. People can add final modifier to private method, but it is meaningless. Note that in derived class, you can define method with same name and parameter types, but it is NOT overriding, since private methods are totally invisible in derived class.

If a class is final, it cannot have any derived class.

Expecting a method to be final means it cannot be override. However, your expectation may not be reasonable. An example is Vector class in previous version of Java. Final methods make late implement of Collections use ArrayList instead.

At the end of this captor, it emphasize again that statics are initialized at the first use of the class, it can be when the first object of that class (includes derived class) is constructed, or when a static field or static method is accessed.

TIJ chapter 6: Access Control

This chapter is not a complex one. It just tells the access control involved in Java.

There are 4 access level in Java, public,  protected, package-private, private. (By accident they all start with letter “p”). Package-private is the default one without any modifier. The only thing one should note is the protected access level implies package-private ones(Actually this is true for all 4 levels, one implies the other one by order).

If one doesn’t allocate a package for a class, this class will belong to the default package. Default package in a same directory is viewed as one package.

People can make use of the access control to reach certain “design patterns”(which is in derision by C programmers). For instance, to create a class that only one instance is available.

TIJ chapter 5: Initialization and Cleanup

This chapter is really the beginning of OOP. I think Java is really designed with the concept of OOP. Even those process oriented programming elements are forced to be absorbed in that systems and become static element. If in one day, which may not be too far away, OOP are no longer popular, Java would either.

Ironically, we always had to have some place to start up a program, and that place can’t be an non-static method, at which no object has been created since it is the beginning. So, the starting point is always a static method, either main() method or something else in JUnit or things like that. In that static method, we can call other static methods or create new objects and run non-static method on that. However, every static method cannot go beyond classes.

Yesterday, one of my friends asked me questions about calling a method in another methods. I hadn’t think into this problem systemically, and hence I summarized all situations: in a static method, you can call other static methods in same class and omit class name, call other classes’s static methods, and call non-static methods via objectname.method; in a non-static method, in additional to the above, you can also call method of this object omitting “this.”. My friend said that the reason he was confused is that an omitted prefix can be either “classname.” or “this.”. I told him, force POP into Java’s OOP system as static fields is what the problem is.

According to the book, how non-static method works is Java inwardly take the object as an additional parameter of the method. Actually, python also do this, but in public: first parameter must be “self ” in this case.

And it also solved a doubt: why some method return this, since this should be known when called; in this case, multiple operations can be operated in one line.

“this” has another use: use this(paras…) as constructor in other overloading constructors, but only once at the beginning of other constructor, and must be at the very beginning, like “super”.

It is not a surprise that we cannot expect finalize() to run since people don’t know when garbage collection work. The book point out that two situations where finalize() is needed: one is when you are using JNI since C/C++ don’t have GC systems. The other is to verify the ending condition.

Other parts of the class is about initialization. Basically, programmers must manually initialize local variables. For fields, things are more flexible. It has a default value. Also, the value can be set by programmer. Basically, those initialization is by order, which means methods which has been defined can be called. However, even if fields are separated by methods, all of them will be initialize. When a class have static fields and blocks, they will always be initialized first when the containing class are referred, either static or non-static. However, those initializations only run one time. Then, every time an instance are created, non-static fields and blocks will be initialized. After that, the constructor runs.

Thinking in Java Chapter 1&2: Object

After one year of programing with Java, I am gradually familiar with OOP. Learning java for me, whose first programming language is C, was much more than change the name system, like field, method, reference, etc. It is almost a renewal of concept. Although so, my knowledge of Java was founded from all kinds of sources, and a book like Thinking in Java seems useful for me to introduce systematically introduce the thought behind Java.

It is important to design classes appropriately. For people who is not familiar with OOP, it can easily happen that use classes as structs and designs methods as “functions” in the outer classes. Abusing inheritance may also be a popular mistake. When the relationship between classes is “have-a”, one should use composition(or aggregation when dynamically). We should also think about it whether the relationship is “is-a” or “is-like-a”. For the former one, we may only override methods of base class, while the latter one may involves implicating new methods. When we upcasting objects to their base classes types, only methods we use substitution can be called. Otherwise, we will have to downcast the reference to call the unique methods. Although so, both the two models are useful, and the choice will be obvious for certain problems.

Fortunately, Java have implemented parameterized types, which is called genetics, to make the downcasting a little bit easier, although some people critic that the genetics make java even more stupid.

Java has a famous system of garbage collector, which I have heard for many times. As a C-programmer, I was used to create pointers to handle complicated data structures. However, in Java, there is no such things anymore. Basically, except some basic data type like int, double, and Boolean, all the objects are reference. It is something like pointer, but its principle is not the same as pointer’s, so it has a different name. When people use new to create an object, java arrange it in heap – like malloc in C. I like to use malloc in C to increase the agility of my codes, but I will have to free the space after use. If I don’t use things like malloc, realloc, calloc, the new variance will be arrange in stack. In Java, you can’t put object other than basic data types in stacks. When the objects are no longer useful, the garbage collector will destroy them automatically, which may cost some time. But anymore, in this way, our life might be easier as developers.

Under this frame, the scope and lifetime in Java may be a little bit different. All the methods and variances(as field) has to be in a class. The class who contains the main method will automatically become something like “main class”. The file name has to be the same as the class name-a interesting system, at least the division of files is more natural than C. A strange thing is, in Java, to “hide” a variable in a larger scope is not allowed, which is legal in C, and, if I remembered, Python.

Only the variance as a field in a class has been initialized automatically, those in method didn’t. Well, I think initializing field manually is necessary, unless those fields are not important in certain cases.

Javadoc is also a useful tool to build manuals for other developers. In the past, I have read a lot of documents in form of Javadoc htmls. I have to admit that they are convenient, either read or build.

I will continue explore in this book, although I prefer the idea behind Python. Anyway, Java is very popular, and learning more doesn’t hurt, does it? Moreover, I found myself begin to love it, at least in some aspects:)

CSAPP chapter 2 : Representation of Data

During the undergraduate studying process, students are familiar with the representation of integers and fractional numbers inside the machine. As a result, this chapter may be kind of basic. However, some interesting facts do exists, which I never think about before.

For instance, we all know that when computing with int and float data, all the data will be cast to float to make sure the loss of data being deduced. To get a result of 0.4, use

to make the cast.

Actually, this also happens when computing with int and unsigned, but I didn’t notice that since the two datatype have the same amount of information, and casting from one to the other wouldn’t noticeable when doing arithmetic.

However, things happen when doing relational operations, like “<” and “>”. All is casted to unsigned, so the -1 < 0 is true, while -1 <(unsigned) 0 becomes false.

Automatic casting also happens for constant. According to C99,

An integer constant begins with a digit, but has no period or exponent part. It may have a prefix that specifies its base and a suffix that specifies its type.

which means a negative number is not constant. When you enter -2147483648, the constant is 2147483648 and then it is negated. For a 32-bit machine, it is overflowed for int, which is the same as long. According to C99, the complier will try int->long->long long. So the result will be  -2147483648 but the type will be long long, which is unexpected. That’s the reason why we got in limits.h like this:

TBC