COMPILER, ASSEMBLER, LINKER AND LOADER

C++ Topics

Beginner: Level 1 [Refer Textbook]
  1. Some Basics
  2. Classes and Objects
  3. Constructors and Destructors
  4. Operator Overloading
  5. Inheritance
  6. Polymorphism, Pointers and Virtual functions
  7. Templates
  8. Exception Handling
Advanced:  Level2

References:
  1. Constructors/Destructors (in depth)
  2. Storage class and Linkage
  3. Overloading and Overriding
  4. Pure Virtual Functions
  5. RTTI
  6. Conversions
  7. Exceptions
  8. Operator Overloading
  9. Auto Pointers
  10. Templates
  11. Name Look-up and Using Declarations
  12. Shallow Copy and Deep Copy
  13. Virtual Table
  14. Miscellaneous Topics

Static and dynamic libraries

A library is a package of code that is meant to be reused by many programs. Typically, a C++ library comes in two pieces:
1) A header file that defines the functionality the library is exposing (offering) to the programs using it.
2) A precompiled binary that contains the implementation of that functionality pre-compiled into machine language.
Some libraries may be split into multiple files and/or have multiple header files.
Libraries are precompiled for several reasons. First, since libraries rarely change, they do not need to be recompiled often. It would be a waste of time to recompile the library every time you wrote a program that used them. Second, because precompiled objects are in machine language, it prevents people from accessing or changing the source code, which is important to businesses or people who don’t want to make their source code available for intellectual property reasons.

There are two types of libraries: static libraries and dynamic libraries.
     A static library (also known as an archive) consists of routines that are compiled and linked directly into your program. When you compile a program that uses a static library, all the functionality of the static library becomes part of your executable. On Windows, static libraries typically have a .lib extension, whereas on linux, static libraries typically have an .a (archive) extension. One advantage of static libraries is that you only have to distribute the executable in order for users to run your program. Because the library becomes part of your program, this ensures that the right version of the library is always used with your program. Also, because static libraries become part of your program, you can use them just like functionality you’ve written for your own program. On the downside, because a copy of the library becomes part of every executable that uses it, this can cause a lot of wasted space. Static libraries also can not be upgraded easy — to update the library, the entire executable needs to be replaced.

     A dynamic library (also called a shared library) consists of routines that are loaded into your application at run time. When you compile a program that uses a dynamic library, the library does not become part of your executable — it remains as a separate unit. On Windows, dynamic libraries typically have a .dll (dynamic link library) extension, whereas on Linux, dynamic libraries typically have a .so (shared object) extension. One advantage of dynamic libraries is that many programs can share one copy, which saves space. Perhaps a bigger advantage is that the dynamic library can be upgraded to a newer version without replacing all of the executables that use it.
Because dynamic libraries are not linked into your program, programs using dynamic libraries must explicitly load and interface with the dynamic library. This mechanisms can be confusing, and makes interfacing with a dynamic library awkward. To make dynamic libraries easier to use, an import library can be used.

    An import library is a library that automates the process of loading and using a dynamic library. On Windows, this is typically done via a small static library (.lib) of the same name as the dynamic library (.dll). The static library is linked into the program at compile time, and then the functionality of the dynamic library can effectively be used as if it were a static library. On Linux, the shared object (.so) file doubles as both a dynamic library and an import library.


Copy constructor and Assignment operator

Although using the assignment operator is fairly straightforward, correctly implementing an overloaded assignment operator can be a little more tricky than you might anticipate. There are two primary reasons for this.
First, there are some cases where the assignment operator isn’t called when you might expect it to be.
Second, there are some issues in dealing with dynamically allocated memory (which we will cover in the next lesson).
The assignment operator is used to copy the values from one object to another already existing object. The key words here “already exist”.
Consider the following example:
Cents cMark(5); // calls Cents constructor
Cents cNancy; // calls Cents default constructor
cNancy = cMark; // calls Cents assignment operator
In this case, cNancy has already been created by the time the assignment is executed. Consequently, the Cents assignment operator is called. The assignment operator must be overloaded as a member function.
What happens if the object being copied into does not already exist? To understand what happens in that case, we need to talk about the copy constructor.

The copy constructor
Consider the following example:
Cents cMark(5); // calls Cents constructor
Cents cNancy = cMark; // calls Cents copy constructor!
Because the second statement uses an equals symbol in it, you might expect that it calls the assignment operator. However, it doesn’t! It actually calls a special type of constructor called a copy constructor. A copy constructor is a special constructor that initializes a new object from an existing object.
The purpose of the copy constructor and the assignment operator are almost equivalent — both copy one object to another. However, the assignment operator copies to existing objects, and the copy constructor copies to newly created objects.
The difference between the copy constructor and the assignment operator causes a lot of confusion for new programmers, but it’s really not all that difficult. Summarizing:
  • If a new object has to be created before the copying can occur, the copy constructor is used.
  • If a new object does not have to be created before the copying can occur, the assignment operator is used.
There are three general cases where the copy constructor is called instead of the assignment operator:
   1. When instantiating one object and initializing it with values from another object (as in the example above).
   2. When passing an object by value.
   3. When an object is returned from a function by value.
In each of these cases, a new variable needs to be created before the values can be copied — hence the use of the copy constructor.
Because the copy constructor and assignment operator essentially do the same job (they are just called in different cases), the code needed to implement them is almost identical.
An overloaded assignment operator and copy constructor example
Now that you understand the difference between the copy constructor and assignment operator, let’s see how they are implemented. For simple classes such as our Cents class, it is very straightforward.
Here is a simplified version of our Cents class:
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents=0)
{
m_nCents = nCents;
}
};
First, let’s add the copy constructor. Thinking about this logically, because it is a constructor, it needs to be named Cents. Because it needs to copy an existing object, it needs to take a Cents object as a parameter. And finally, because it is a constructor, it doesn’t have a return type. Putting all of these things together, here is our Cents class with a copy constructor.
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents=0)
{
m_nCents = nCents;
}
// Copy constructor
Cents(const Cents &cSource)
{
m_nCents = cSource.m_nCents;
}
};
A copy constructor looks just like a normal constructor that takes a parameter of the class type. However, there are two things which are worth explicitly mentioning. First, because our copy constructor is a member of Cents, and our parameter is a Cents, we can directly access the internal private data of our parameter. Second, the parameter MUST be passed by reference, and not by value. Can you figure out why?

 The answer lies above in the list that shows the cases where a copy constructor is called. A copy constructor is called when a parameter is passed by value. If we pass our cSource parameter by value, it would need to call the copy constructor to do so. But calling the copy constructor again would mean the parameter is passed by value again, requiring another call to the copy constructor. This would result in an infinite recursion (well, until the stack memory ran out and the the program crashed).
Fortunately, modern C++ compilers will produce an error if you try to do this:
C:\\Test.cpp(431) : error C2652: 'Cents' : illegal copy constructor: first parameter must not be a 'Cents'
The first parameter in this case must be a reference to a Cents!
Now let’s overload the assignment operator. Following the same logic, the prototype and implementation are fairly straightforward:
class Cents
{
private:
int m_nCents;
public:
Cents(int nCents=0)
{
m_nCents = nCents;
}
 
// Copy constructor
Cents(const Cents &cSource)
{
m_nCents = cSource.m_nCents;
}
 
     Cents& operator= (const Cents &cSource);
 
 };
 
 Cents& Cents::operator= (const Cents &cSource)
 {
     // do the copy
     m_nCents = cSource.m_nCents;
 
     // return the existing object
     return *this;
 }
A couple of things to note here: First, the line that does the copying is exactly identical to the one in the copy constructor. This is typical. In order to reduce duplicate code, the portion of the code that does the actual copying could be moved to a private member function that the copy constructor and overloaded assignment operator both call. Second, we’re returning *this so we can chain multiple assigments together:
cMark = cNancy = cFred = cJoe; // assign cJoe to everyone
If you need a refresher on chaining, we cover that in the section on overloading the I/O operators.
Finally, note that it is possible in C++ to do a self-assignment:
cMark = cMark; // valid assignment
In these cases, the assignment operator doesn’t need to do anything (and if the class uses dynamic memory, it can be dangerous if it does). It is a good idea to do a check for self-assignment at the top of an overloaded assignment operator.
Here is an example of how to do that:

Cents& Cents::operator= (const Cents &cSource)
 {
     // check for self-assignment by comparing the address of the
     // implicit object and the parameter
     if (this == &cSource)
         return *this;
 
     // do the copy
     m_nCents = cSource.m_nCents;
 
     // return the existing object
     return *this;
 }
Note that there is no need to check for self-assignment in a copy-constructor. This is because the copy constructor is only called when new objects are being constructed, and there is no way to assign a newly created object to itself in a way that calls to copy constructor.

Default member-wise copying
Just like other constructors, C++ will provide a default copy constructor if you do not provide one yourself. However, unlike other operators, C++ will provide a default assignment operator if you do not provide one yourself!
Because C++ does not know much about your class, the default copy constructor and default assignment operators it provides are very simple. They use a copying method known as a memberwise copy (also known as a shallow copy).
Source:

Copy constructor and Copy Assignment operator in c++

This article contains explanations on:
- overloaded copy constructors
- overloaded copy assignment operators
- shallow copy vs deep copy

1. We need to keep in mind that there are certain functions that the C++ compiler automatically provides for us. That is, even if we do not provide these functions explicitly when we write our classes, the compiler will provide them by default. Among them are:
- copy constructor
- default constructor
- copy assignment operator
- destructor
The constructor and destructor which are provided to us by the compiler don’t actually do anything special. They just sit there and do nothing.
Note that the default constructor provided automatically by the compiler does not take any parameters. i.e. it is parameterless. (which is quite obvious, since it actually does nothing so as to require any parameters.)

2. Another interesting thing to note is that if we provide any parameterized constructor (i.e. a constructor that takes one or more parameters) the default parameterless constructor provided automatically by the compiler vanishes.
Take this example:
class MyClass
{
public:
MyClass (int value) //parameterized constructor provided by us.
{
x = value;
}
private:
int x;
};
Now, as we can see we have provided a parameterized constructor by ourselves for our class.
So, the compiler responds by not providing to us by default any parameterless constructor.So, if we write in the main program, something like:
MyClass obj; //error
The compiler would generate an error, because the way we are trying to instantiate the class in the above statement requires a parameterless constructor, but neither have we explicitly provided one, nor has the compiler automatically provided one.
Hence, the rule to remember is this: if we would have any need for a parameterless constructor, either provide no constructor at all (i.e. not even a parameterized constructor) so that the compiler can provide us with a parameterless constructor automatically or, if you are anyway going to provide a parameterized constructor, make sure that you also provide a parameterless constructor.
i.e. in our example, we can modify that as follows:
class MyClass
{
public :
MyClass (int value)
{
x = value;
}
MyClass ( )
{
x = 10;
}
private:
int x;
};

3. Assignment vs copy construction
Copy constructors are used in a variety of situations. Two of them are as follows:
- X obj1 (obj2); //constructing obj1 as a copy of obj2.... copy constructor called.
- X obj1 = obj2; // again, same as above.
In contrast, in the following code segment, the copy assignment operator is invoked:
X obj1;
obj1 = obj2; //assignment, not construction.

4. The copy constructor and the copy assignment operator provided to us by default by the compiler also do what are they are supposed to do - i.e. create a new copy of an object, or assign one object to another, in the most simple way possible.
They do a shallow copy and not a deep copy.
Let us see that through an example.
class X
{
public:
X (int value1, value2)
{
data1 = value1;
data2 = value2;
}
X ( )
{
data1 = data2 = 10;
` }/
/some functions here, but no copy constructor or copy assignment operator.
private:
int data1;
int data2;
};
Now, let us see what happens in the following statements:
X obj1 (10, 20); // obj1 is constructed using parameterized constructor of X.
X obj2 (obj1); //here, we are invoking copy constructor of X to construct obj2 as a
copy of obj1.
But, we have not explicitly provided any copy constructor. So, the copy
constructor provided by the compiler is called.
It constructs obj2 by copying:
- obj1.data1 into obj2.data1
- obj1.data2 into obj2.data2
Similarly, if we have the following statements:
X obj3 (100, 200); //parameterized constructor called.
obj3 = obj1; //copy assignment operator called. Since we do not provide one,
compiler’s version is used.
The compiler’s copy assignment operator just copies obj1.data1 into
obj3.data1 and obj1.data2 into obj3.data2.

5. When does the compiler’s version of copy constructor and copy
assignment operator fail?
Answer: When what we want is a deep copy and not a shallow copy. That
is, when we have any member variable which is a pointer.
Let us see the following example:
class MyClass
{
public:
//some functions, but no copy constructor or copy assignment operator.
private:
int data;
int* ptr;
};
Now, as we can see, the member variable of our class contains a pointer
variable. This means there will be trouble if we call the compiler’s version of copy constructor and assignment operator.
Take, for instance, what happens when we write:
MyClass obj2 (obj1); //assume that obj1 is already constructed earlier.
Now, the compiler’s copy constructor will perform the following operations:
obj2.data = obj1.data;
and obj2.ptr = obj1.ptr;
The statement obj2.data = obj1.data is okay. There is no problem with that. But the statement obj2.ptr = obj1.ptr is trouble for us.
What that statement means is that both obj2.ptr and obj1.ptr will point to
the same place in memory. That is not what we want. This is what is known as shallow copy -- simply copying the pointers, and not the underlying data being pointed to by the pointers.
What we wanted is this: suppose obj1.ptr was currently pointing to an
integer whose value is 1000. Then, we want that obj2.ptr should point to some  other location in memory, where also the value of the integer stored is 1000. This is what is known as deep copy -- i.e. copying the underlying data being pointed to by a pointer, and creating a new pointer to point to that new location.
Similarly, the compiler’s copy assignment operator performs a shallow copy
instead of a deep copy.
So, to summarize, the compiler’s copy constructor and copy assignment
operator fail when what we what is a deep copy and not a shallow copy. i.e. when we have a pointer member variable in our class.

6. Overloading the copy constructor:
We can provide our own copy constructor for our class. When we do so, it is
said that we are overloading the copy constructor. When we provide our own copy constructor, obviously the compiler’s version of copy constructor will no longer be called.
Let us see how to write a copy constructor for our class.
class MyClass
{
public:
MyClass (const MyClass& param); //copy constructor
private:
int data;
int* ptr;
};
As we can see, the copy constructor takes as parameter the object which we
want to copy. In general, we will always use a parameter which is reference-to-const as in the example above.
Now, we need to define the copy constructor:
All we do is to copy all member variables of our parameter, making sure
that we are doing a deep copy.
MyClass :: MyClass (const MyClass& param)
{
//copy data member variable
data = param.data; //also can be written as : this -> data = param.data;
//deep copy ptr member variable variable
// two steps we need to do for this
// 1. create a new pointer using new operator
// 2. that newly created pointer should point to a value which is the same as
that pointed to by param.ptr. i.e. if param.ptr is pointing to 10000, then this new pointer
should also to 10000.
ptr = new int;
*ptr = *param.ptr;
//or, we could combine both these statements into one: ptr = new int (*param.ptr);
}
--------------
So, we saw the following facts about how to write our own copy
constructor:
(a). The parameter for the copy constructor is const ClassName& param. (ie reference to const)
(b) Copy all member variables of param into our (this) object, keeping in
mind to do deep copy whenever pointer variables are involved.
-------------

7. How to write overloaded copy assignment operator?
There are 4 things to remember when writing copy assignment operator:
(two of them are the same as for copy constructor)
(a) The parameter for the copy constructor is const ClassName& param. (i.e.
reference-to-const)
(b) Copy all member variables of param into our (this) object, keeping in mind to do deep copy whenever pointer variables are involved.
( c) Return type of copy assignment operator is ClassName & (i.e. reference
type)
(d) Guard against self copy (i.e. statements like : obj1 = obj1; )
Let us look at an overloaded copy assignment operator through example:
class MyClass
{
public:
MyClass& operator= (const MyClass& param) ;
//Note the following:
// return type is : MyClass&
// parameter type is : const MyClass& (this is usually how objects are generally
passed as parameters to most functions. So, nothing special here.
// name of function : operator=.
private:
int data;
int* ptr;
};
Now, let us write the implementation for the assignment operator that we have
overloaded:
MyClass& operator= (const MyClass& param)
{
int* temp; // a temporary pointer
if (this != &param )
//this is very imp --- guarding against self assignment (i.e. obj1 = obj1)
// if LHS and RHS of assignment are the same object, then don’t do anything.
{
//copy the member variable “int data”
data = param.data; //or, this->data = param.data;
//deep copy member variable “int* ptr”
//take care to delete old copy of this->ptr
temp = new int (*param.ptr); //temp is a newly created pointer.
//delete the old this->ptr;
delete ptr;
//assign ptr to temp
ptr = temp;
}
//finally return (*this)
return *this;
}

Source: