Introduction

Writing programs in C++ requires a thorough understanding of its language features. As C++ is a very rich language understanding all these features and applying them at the right place in programms requires a lot of experience. In these notes I try to summarize my experience in this wonderful programming language. To learn C++ one need to program, that is solve some problem with a computer.

We can not remember every detail therefore we need references:

C++ Overview

A program consists of human readable text which we call code. The code is stored in a source file. The code must obey the formal rules of the programming language used. The source file is translated by a program, called compiler, into an object file containing only machine instructions. Another program, the linker, translates a number of object files into a machine executable file. The process of writing programs consists of: writing source code, compiling source codes into object files and then linking object files into an executable file. The steps of compling and linking are machine and vendor dependent. However the specifications of the source code are standardized by the C++ Language specification.

Although a program could be written in one source file this is in practice not done. For a C++ program two type of files are distuinguished: source files (ending with .cpp) and header files (ending with .h). A source file contains the code the computer must execute and also #include directives for including header files. The header files for system libraries are included between brackets and for private libraries between quotes. The first step of the compiler is then preprocessing the source files: a) macro processing and b) bring in the header files defined by the #include directives. The result of this preprocessing is a translation unit. A translation unit contains all the code needed for a compiler to translate the source code into machine instructions.

Machine code is essentially very simple. Each instruction consists of a reference to one or more data items and an operation on these data items. Operations can be: movement of data from one place to another, basic arithmetic and logical operations, and program flow operations.

The essence of a programming consists of two activities:

For the declaration of variables there are two classes of data types available: fundamental data types and user defined types.

Fundamental data types

Fundamental data types correspond to data types available at the machine level implementation. These data types have built in arithmetic operators: and comparison operators:

User defined data types

User defined types (UDT) allows the programmer to define its own types and operations on these types. C++ has many ways to accomplish this: structures, classes, and templates. The proper way to organize the code of a user defined type is to separate the declaration from the definition. the declaration is put in a header file and the definition into a source file. The interface header file is included in both the source where the UDT is used as well as in the implementation file of the UDT.

Statements

Statements in C++ fall into two classes: simple statements and control statements. A simple statement consists of an expression—typically an assignment or a function call—followed by a semicolon. The control statements are: The first two are used to express conditional execution, while the last two are used to specify repetition.

Functions

C++ programs are typically subdivided into several functions. Each function consists of a sequence of statements that can be invoked by writing the name of the function,followed by a list of arguments enclosed in parentheses. These arguments are copied into the corresponding parameter variables inside the function. The function can return a result to the caller by using the return statement and can share values using reference parameters. A C++ program contains at least one function, called main. This is the first function that is executed.

Learning C++ is learning the details about available functionality on data-types, statements and functions.

Classes

Class declaration

Classes are user-defined types needed to achieve a higher abstraction level than just the fundamental types. A struct is similar to a class where all members are public (no access restrictions). In a class the members are by default private (only member functions can access the member data by default), but with the access specifiers: private and public this can be modified. A class consists of member data and member functions. The member functions of a class are usually defined outside the class declaration. The function name need to be prefixed with the class name and ::. This is called scope resolution and is needed so the compiler can make the link between the class and the function. In fact, the definitions are often put in a separate file and compiled separately. The point is that application programs that use the class need only know what the objects can do; they do not need to know how the objects do it. The function declarations tell what they do; the function definitions tell how they do it. A member function defined within the class definition – rather than simply declared there – is taken to be an inline member function. That is, inclass definition of member functions is for small, frequently used functions. Instead of definining the function within the class declaration, one can alternatively define the function as an inline function after the class declaration in the same file. When the member function definitions are separated from the declarations the declaration section is called the class interface, and the section containing the member function definitions is called the implementation. The interface is the part of the class that the programmer needs to see in order to use the class.

When a class has been declared objects of this class can declared, this is called instantiation, the resulting object is called an instance of the class.

// declaration of a class class T { // declaration of a class T public: void f(int); // public member function private: int d; // private data member }; int main() { T x; // declare variable of class T x.f(3); // call the member function on instance x } void T::f(int _d) { // use scope resoution d=_d; // access of private data members via member function }

Constructors and destructors

A class’s constructor “constructs” the class objects by allocating and initializing storage for the objects and by performing any other tasks that are programmed into the function. A constructor has the same name as the class. Multiple constructors can be defined, with different argument lists. A default constructor is a constructor that can be called without supplying an argument. If no constructors are defined explicitly the compiler will try to generate one. Because const and references must be initialized, a class containing const or reference members cannot be default constructed unless the programmer explicitly supplies a constructor.

Most constructors do nothing more than initialize the object’s member data. Consequently, C++ provides a special syntactical device for constructors that simplifies this code. The device is an initialization list. The list starts after the parameter specification and begins with a colon and precedes the function body. Initialization lists are essential for types for which assigment does not work, that is for member objects of classes without default constructors,for const members and for reference members.

Often it is usefull to specify default values for the parameters which should be used if no parameter value is supplied.

The instantiated objects occupy memory different from the class where the member functions are stored. Each non-static member function maintains a pointer, named “this”, which points to the object that is calling it. The expression *this refers to the object for which a member function is invoked. Most use of this is implicit.

Constructors are called when an object comes to live, destructors when it is destroyed. Destructors are called implicitly when an automatic variable goes out of scope, an object on the free store is deleted, etc. Only in very unusual circumstances does the user need to call a destructor explicitly. The most common use of a destructor is to release memory acquired in a constructor.

If a class has class objects as members then the member objects are constructed first, based on the initialization list, in the order of declaration. When the class is destroyed the objects own destructor is executed first and then the members destructors in reverse order of declaration.

In a class only static integral constant members can be initialized.

// definition of a class with constructor, initialization list and default parameters class Ratio { public: Ratio(int n=0,int d=1) : num(n),den(d) {reduce();} // constructor with default values and initialization list Ratio(const Ratio& r): num(r.num),den(r.den) {} // copy constructor int numerator() const { return num; } // read-only access to private data int denominator() const { return den; } // read-only access to private data private: void reduce(); int num,den; }; void Ratio:reduce() { ... } int main() { Ratio x(4),y(x); }
Every class has default two constructors, a copy assignment operator, and a destructor which are automatically created: If either of these are not defined explicitly, then it is automatically defined implicitly by the system. Note that the copy constructor takes one parameter: the object that it is going to copy. That object is passed by constant reference because it should not be changed. The copy constructor and assignment operator copy the complete state of an existing object into a new object of the same class. The copy constructor is called automatically whenever:

You only need to define a copy constructor and assignment operator explicitly if a memberwise copy is not what you need. This is normally the case if member objects are pointing to data. In that case the memberwise copy can result in disastrous behavior. Below is an example that deals with this situation. The reason why the assignment operator returns a reference to an object, is to allow chained calls for the operator. Essentially x=y=z=4; is shorthanded for x.operator=(y.operator=(z.operator=(4)));

A constructor with one argument should normally be defined with the keyword explicit. This avoids that the compiler unintentionally constructs an object with an assignment operator. So if s is a string object, with implicit construction the compiler translates s=10 into s("10") instead of creating an empty string of 10 positions. This is unnoticed for the programmer at compile time and should be avoided.

// definition of a class that allocates memory class Name { const char* s; //.. }; class Table { Name* p; size_t sz; public: Table(size_t s=15) {p = new Name[sz=s];} // constructor ~Table() {delete[] p;} // destructor Table(const Table&); // copy constructor Table& operator=(const Table&); // copy assignment }; Table::Table(const Table& t) { p = new Name[sz=t.sz]; for(int i=0;i<sz;i++) p[i]=t.p[i]; } Table::Table& operator=(const Table&) { if(this!=&t) { //avoid self-assignment delete[] p; p= new Name[sz=t.sz]; for(int i=0;i<sz;i++) p[i]=t.p[i]; } return *this; }

Static members

Static members are part of a class, but not part of an object of that class. There is exactly one copy of a static member. Also a function that need access to members of a class, but does not need to be invoked for a particular object is called a static member function. Because static member functions are not attached to an object, they have no this pointer. Static member functions do not work on an object, so the this pointer is not needed. Second, static member functions can only access static member variables. They can not access non-static member variables. This is because non-static member variables must belong to a class object, and static member functions have no class object to work with.

// declaration of a static member function: num() and a static member data: count class Widget { public: Widget() { ++count; } ~Widget() { --count; } static int num() { return count; } private: static int count; }; int Widget::count = 0; int main() { Widget x,y,z; cout << Widget::num(); }

Constant member functions

Like variables and function parameters also member functions can be defined const: T f() const{};A const member function does not modify the state of an object. Also objects may also be declared to be constant. A const member function can be invoked for both const and non-const objects, whereas a non-const member function can be invoked only for non-const objects.

Pointers to class objects

// (*p).data <=> p->data class X { public: int data; }; int main() { X* p = new X; (*p).data = 22; // . has higher precedence than * therefore parentheses required p->data = 22; // same meaning, but prefered reference method cout << p->data << endl; }

Overloading operators

C++ includes a rich store of 45 operators. These operators are defined automatically for the fundamental types (int, float, etc.). When you define a class, you are actually creating a new type. Most of the C++ operators can be overloaded to apply to your new class type. There are binary and unary operators. A binary operator can be defined by either a nonstatic member function taking one argument or a nonmember function taking two arguments. For example:

// binary operator overloading with member and non-member functions class X { public: void operator+(int); X(int); }; void operator+(X,X); void operator+(X,double); void f(X a) { a+1; //a.operator+(1) 1+a; //::operator(X(1),a) a+1.0; //::operator(a,1.0) }
An unary operator, prefix or postfix, can be defined by either a nonstatic member function taking no arguments or a nonmember function taking one argument. @aa can be interpreted as aa.operator@() or operator@(aa). If both are defined, overload resolution determines which interpretation is used.

Assignment overloading

We have already seen the assignment operator overloading earlier. The correct syntax is:
// assignment operator overloading T& T::operator=(const T& t) { // assign each member datum of t to the // corresponding member datum of the owner return *this; }

Functors

Functors (also called function objects or functionoids) are one of the most powerful features of the C++ language, especially in conjunction with STL algorithms. In C++, to create a functor, you create a class that overloads the parentheses operator, operator ( ).


class Convert
{
		public:
			explicit Convert(const double factor): _factor(factor) {}
		double operator() (const double amount)
		{
			return amount*_factor;
		}	
		private:
			double _factor;
};
Now with this functor we can easily use the advantage to store a conversion factor between multiple function calls.

main()
{
  Convert meters_to_miles(0.000621371192);
  double distance_in_meters=1200;
  double distance_in_miles=meters_to_miles(1200);
}

Enum types

In C and C++, enum types can be used to set up collections of named integer constants. (The keyword enum is short for enumerated.)


#define SPRING   0
#define SUMMER   1
#define FALL     2
#define WINTER   3

An alternate approach using enum would be


enum { SPRING, SUMMER, FALL, WINTER };

If you don't specify values for enum constants, the values start at zero and increase by one with each move down the list. If you want, you may provide explicit values for enum constants, as in


enum FooSize { SMALL = 10, MEDIUM = 100, LARGE = 1000 };

There are two kinds of enum type declarations. With and without a name. If you give an enum type a name, you can use that type for variables, function arguments and return values.


FooSize x=MEDIUM;

There is an implicit conversion from any enum type to int. But not the reverse


int i = SMALL; // i=10
FooSize x=10;  // error

Libraries

It is a good design principle to organize code in modules. In C++ modules are libraries. To use a library in a c++ source file, the related library header file should be included or the called functions or objects are declared with the extern tag. There are different type of library files. Static and dynamic. The code used from a static library file is included by the linker in the EXE program. The code from a dynamic library file, dll remains separate from the EXE and is called during runtime. There are two forms of linking with a dll: implicit and explicit. With implicit linking the executable using the DLL links to an import library (.lib file) provided by the maker of the DLL. The operating system loads the DLL when the executable using it is loaded. The client executable calls the DLL's exported functions just as if the functions were contained within the executable. With explicit linking, the executable using the DLL must make function calls to explicitly load and unload the DLL and to access the DLL's exported functions. The client executable must call the exported functions through a function pointer. An executable can use the same DLL with either linking method. Furthermore, these mechanisms are not mutually exclusive, as one executable can implicitly link to a DLL and another can attach to it explicitly.

Dynamic library files have some advantages over static library files: 1) can be used by multiple EXE files, 2) updates are easier 3) smaller sized EXE files. A

Visual Studion
Creating a library: specify the project type in the project - properties window:

Additional for a dynamic library one has to specify for each function which is exposed to be called by an external program the following specifier: __declspec(dllexport).

To use the library the linker must be able to find the library. For libraries where the source code is available one can add a project dependency to the project.

For other libraries you can use the drag-and drop method, drag the .lib file to your project solution window. So for dynamic libraries do not use the dll file.

or alternatively use the configuartion section of the project properties and specify the additional dependencies:

For dynamic libraries the include header file should contain the following specifier __declspec(dllimport) for each imported function from the library. A reuable header file could have following form:

To define your exports, you must go to Project->Properties->C/C++->Command Line and add the flag /D. This stands for define. In this specific case, you are defining BUILD_DLL, which means you intend to implement this library as an export. Users of the library would not be defining the variable if they intended to use the library.

CRT Libraries
The CRT in a nutshell is all the library functions you rely on to develop your code. It includes the Standard C++ Library as well as the Microsoft functions and declarations. This is a summary list of the libraries you can integrate with. For the full list, see MSDN.

To set your version of the CRT, go to 'Project Properties->Code Generation->Runtime Library' and select either /MT, /MTd, /MD, or /MDd, (Multithreaded[debug] or Multithreaded DLL[debug]). "If you design your DLL so that it passes CRT objects across the boundary or allocates memory and expects it to be freed outside the DLL, you restrict the DLL users to use the same copy of the CRT library as the DLL. The DLL and its users use the same copy of the CRT library only if both are linked with the same version of the CRT DLL." The version of CRT used for compiling the library can be found with following command line command:
 dumpbin /imports 
 
See MSDN.

MS provides a way to compile the CRT libraries so that you can package them with your library. To compile your own version of CRT, go to the VS Command Line Tool. (Ensure that you have Administrator rights by right clicking on the VS Command Line Tool and selecting 'Run as Administrator'.) Type 'set vctools=C:\Program files\Microsoft Visual Studio x.x\VC' (where x.x is your version of VS). Then type 'crt\src\bldnt.cmd'. This will build the CRT libraries. This will run for a minute or so, compiling all the necessary libraries for your system. Once completed, I received 'libcmt.lib', 'libcpmt.lib', '_sample_.dll', and '_sample_.lib'. The sample files are actually copies of msvcrXX.dll (where XX is your VS version). They are renamed so that they do not conflict with the actual MS libraries. Once you have built your custom libraries, you need to link them into your project. To link them into your project, you have to get back into the Project Properties and add them as previously taught. Since you are linking the custom CRT libraries, you need to move the default libraries by going to 'Project Properties->Linker->Input->Ignore All Default Libraries->Yes'. This will override the default MT or MD flags which will automatically include the standard CRT for your VS versions. However, be warned that once you do this, you will be required to import all the additional dependencies by hand. 'Additional Dependencies=.\_sample_lib', or whatever happened to be your dependencies libraries. The other alternative is just to ignore the default CRT libraries by going to 'Ignore Specific Library=msvcr9.0.lib' and place 'Additional Dependencies '_sample_.lib' so that your library relies on your compiled library and not the system defaults. This allows for greater flexibility when sharing your libraries with customers, as your dependencies get shipped along with your libraries.

References



Copyright ©2012 Jacq Krol. All rights reserved. Created ; last updated .