Few Tips for C++ Programmers

The following list will span some of your problems which you encounter while trying to code in C++(especially if you are beginner). This page will however won't be able to resolve all the obstacles which you will face. But still I feel this will answer most common problems arising with beginners. If you have any suggestion, what more points I can add here, please mail me about it. I will try my best to respond quickly.
  1. Getting rid of nagging warning about backward compatibility while compiling the code:
    This warning message is due to the inclusion of standard header files included in your code file having .h extension. The solution is simple, if you want to include these standard header files, include them by dropping the .h extension. e.g if you are using "#include <iostream.h>", then change it to "#include <iostream>". But by doing this and then compiling the code you will get some errors like cout undeclared (first use this function). Similar errors for cin, endl, etc. Temporarily you can avoid these error message by including the statement "using namespace std;" in your code before you start writing main() function. For better solution refer namespace.
  2. Declare all your classes in separate header files and Implement them in .C file:
    Its always good idea to declare interface of your class in a .h file and implement them in a separate .C file. The name of these files should be preferably same as the class name followed by .h (.C). The .C file can be separately compiled to generated object file (with .o extension). For example if you are writing a class diode, provide its interface in the file 'diode.h' and implement these interfaces in 'diode.C'. The other classes which depends on the class diode, will depend only on the interface and not on how they are implemented (if your design is good). Thus, this class just needs to include diode.h only. Thus, if you ever feel the need to change implementation of some diode's interface (function), you will be changing only diode.C file. Hence, only diode.C has to be compiled.
  3. Use meaningful names to declare your classes, variables and functions:
    This may seem to be a bit painful idea to you. But this make the code more readable and understandable both for you and others. Try to keep the names small enough and suggestive. complex and cmplx will serve as a good name for complex class but not something as small as 'C' or as big as 'mycomplexclass '. The first one is too small to suggest that it represents a well known mathematic concept of complex numbers and their arithmetics. The second one is suggestive but too long to type. It should be easier for others to both remember and type these classes and functions names.
  4. Understand the Concept of namespace:
    Namespace was introduced to relieve the programmers worry of the name clashes of the classes defined in their library with those defined by someone else. Suppose you have designed a library opamp.h and I have designed a library flipflop.h and we both have used a base class chip. Now suppose some third party wants to use both of our library for his simulation project. But when he includes both these libraries and tries to compile it, the compiler will complain something like, defining the class chip again previous declaration in line:xx. To solve the mentioned problem, namespace was introduced. While writing your library you enclose it inside a namespace. Any of the features (class or function) can be only accessed by passing through this namespace. To embed a part or whole of your library in a namespace you use the following syntax:
    namespace PSC{
    //your library goes here....
    //......................
    }
    One nice feature of namespace is that they are open, i.e. you can use the previously declared namespace to embed other libraries. Thats what exactly has been done in standard libraries. All the standard libraries has been defined in namespace std. Suppose you want to access a class say 'Transformer', and declare its instance which you have embedded in namespace 'PSC'. For this you have to use the following statement:

    PSC::Transformer trans1;

    The doublecolon(::) is called scope resolution operator. If you need to use Transformer again and again in your code, accessing it through scope resolution will be a great pain to live with. To avoid it you can use the statement:

    using namespace PSC;

    This will open the whole library for you and you can access any of its functions and classes without the need of scope resolution. But if you want to selectively open a class or function from the library, use:

    using PSC::Transformer;

    This will ensure that other unrequired classes don't open up and possibly collide with some of the classes defined by you or in some other library. So, if you are only interested in using cout, cin, and endl which are the part of iostream library you will use:

    using std::cout;
    using std::cin;
    using std::endl;

    This is what I referred as better solution in first topic in this list of tips.
  5. The other way is to use typedef:
    typedef PSC::Transformer MyTransfomer;
  6. Constructors:
    All the objects which you will develop will hold some memory space, size of which depends on what all are the attributes of that object. For example if an object happens to have int and one float the size of the object will be the sum of the size of one int and one float. If the object happens to hold one pointer the size of the object will be the size of int, irrespective of how huge memory chunk is being addressed by the pointer. To properly initialize the object(assigning proper values to all its attributes and memory from the heap to the pointers) you need to write proper constructor. If the constructor doesn't take any arguments its called default constructor. An object can have more than one constructors. In the constructor you should take care of allocating proper memory space to all the pointers and you shouldn't leave any pointers dangling(uninitialized). If you don't want to allocate any memory to it, assign it the value NULL.
    Now, I have given you the basic idea of what the constructor is really about, which most of you must be aware of it. What I intend to tell you here is something else. Suppose, you have one class(Car) which contains objects of other classes(say engine, tyre, etc in this case). This is called composition.
    	class Car{
    private:
    Engine eng;
    Tyre t1, t2, t3 t4;
    //.....
    //....
    //lots of other stuffs.
    public:
    Car();//default constructor
    Car(some parameters)//constructor
    };
    Now, when the car is constructed, all other composed objects are constructed using its default constructor. But what if you intend to call its some specific constructor, say tyre with particular air pressure and groove size. You can't call tyre's constructor inside the constructor of Car because, those objects are already constructed, before the construction of Car starts. Similarly, if there is some const variable inside the class, you can't initialize it to its constant value inside the constructor's body.
    	class resistor{
    private:
    const resistance;
    //.......
    //.......
    public:
    resistor(float res_value){
    resistance=res_vale;//error, constant variable can't
    //changed
    }
    };
    The solution provided by the language is to use constructor initializer list. This list starts with a colon(:) after the argument list of the constructor and ends before the opening brace. For initializing constant variables, you type the name of that variable and inside parenthesis give its default value, e.g.
    resistor::resistor(float res_value):resistance(res_value){
    //do other stuffs
    //...
    }
    Similarly, to call the composed object's constructor, you call it in initializer list.
    Car::Car(float front_air_pressure, back_air_pressure, float groove_size, engine_parameters, other parameters):/*initializer list begins*/ 
    					/*intialize tyres*/ t1(front_air_pressure, groove_size), t2(front_air_pressure, groove_size), 
    					t3(back_air_pressure, groove_size), t4(back_air_pressure, groove_size), 
    								/*intialize composed class engine*/ eng(engine_parmeters){
    //other stuffs
    //.....
    //.....
    //.....
    }
    Initializer list is also helpful when inheritance is involved. Suppose you have a base class BASE and from it an inherited class DERIVED. When ever a class is constructed, the most base class is constructed first and then towards the derived classes. Hence, when an instance of DERIVED class is constructed, first the BASE part is constructed and then the extra features added by DERIVED. The problem here is same as in the above case. The BASE class is constructed using its default constructor. The solution is same here, You call the constructor of BASE class in the initializer list, but here you use the name of the base class i.e.
    DERIVED::DERIVED(params_for_base, params_for_derived) : BASE(params_for_derived){
    //extra stuffs
    //.....
    }
  7. Destructors:
    OK! You have allocated memory to the object while creating it through constructors. Now, if you don't need it, there's no point in holding that memory space. You should free that memory as soon as you don't need it. You accomplish this task by defining a destructor for that class. In the destructor you will release the memory held by the pointers by using delete operator. All the extra space which is consumed for entities like int, float, char or some user defined data-type will be released automatically once the object goes out of the scope. Only thing you need to do in most of the case is to free the memory addressed by pointers. There might be cases when you don't deallocate memory, when you are sharing that memory chunk among various objects of that particular class.
  8. Copy-Constructors:
    Copy-Constructors are special type of constructor in which the parameter passed is the reference of an object. You can use this constructor to create an instance of the class, but its main utility is to create the local copy of the object when you pass it to some function. If you don't create a copy-constructor, compiler will generate one for you, which in most of the cases, copy the entries of the object to the corresponding entry in the object which is being constructed. If this is what you want, there is no need to declare it. But if you have pointers in your class, you should declare your own copy-constructor, otherwise the pointer of this local object inside the function will happen to point to the same memory location already addressed by the original object. So, when the function completes its execution, the local object's destructor will be called which will free this memory. Hence the pointer inside the original object won't be able to access it, losing all its information. Hence, its really important to declare your own copy-constructor in the case of pointers.

    Now one important point. As I already mentioned that copy-constructors are also constructor, so when a derived class is constructed using copy-constructor, the base class will be constructed with its default constructor. This is in the most case you are not intended to do. You will expect base part of the class to be the copy of the base part of the other class. If the base class has some attributes which are private, the derived class won't have any access to them and hence won't be able to change those attribute in its constructor. The solution is simple. Use initializer list in the same way as you used it to construct the DERIVED class using normal constructors. Only thing you have to do is to call the copy-constructor of the base class:
    DERIVED::DERIVED(const DERIVED& D) : BASE(D){
    //copy parts corresponding to the DERIVED CLASS
    //.....
    }
    Copy-constructor of BASE takes some other object of type BASE by reference. Since DERIVED is being inherited from BASE, it can be passed to the BASE's copy-constructor.
    The concept of initializer list was introduced in C++ to deal with this particular problem only. Later it was extended to cope up with the problems discussed above.
  9. The Annoying and Important keyword const:
    Whether you use const in your program or not, in the large project, it will surely cause lots of annoyance if you are not used to it. To avoid this frustration, you should learn various meanings of the const. You may wonder, How can const have various meanings?
    Yes, you are right. It declares something to be of type constant. But what's the effect of the constantness in various contexts? Lets discuss all of them one by one.
    1. const with variables: This is the one meaning which almost all of you are aware of. If you declare a variable(of inbuilt type or of user defined type) to be const, you won't be able to change its value(until you use const_cast). You have to initialize the const variables at the time of its creation only. This are easy to use alternatives to #define macros. In place of "#define PI=3.14159" you can now declare "const double PI=3.14159" If you find that some variable shouldn't change its value in its entire lifetime, you should declare it to be const, so that compiler can flag error, if by mistake you happen to change it.
    2. const with pointers: Suppose you declare something like this in your code:
      const int* ptr=new int;
      To whom is constantness is binded? Pointer or Pointed object? The ans is pointed object. So the following is legal:
      	int u;
      	int v;
      	const int* ptr=&u;
      	ptr=&v;//OK, pointer can be changed
      But not the following:
      	int u=3;
      	const int* ptr=&u;
      	*ptr=4;//error, pointer is declared to address const int
      As pointer is being declared to point to const object and not itself being const, it can be declared without being initialized:
      	const int* ptr;//Ok, no initialization of ptr needed.
      
      Now, suppose you want to declare pointer itself to be constant, so that the pointer cannot change its value and hence, will point only one object during its existence. Most of us will declare following when asked to do this for the first time in our life:
      	 int const* ptr;
       
      But this means the same as above, ptr happens to address a constant object. To declare pointer itself to be constant, use the following segment:
       	int* const ptr=&someint;
       
      Now you can't make ptr to point to something else, but you can change the value of the object being pointed by it. To declare a const pointer which points to an const object any of the two segment is ok:
       	int x=2;
      	const int* const ptr1=&x;
      	int const* const ptr2=&x;
       
    3. Passing one or more argument to a function as const: When you pass an argument to a function as const, it doesn't mean that you can't pass non-const object as an argument to that object. Only thing you are telling the compiler is that this variable has to retain its value during the execution of that function. So, if by mistake you try to change its value inside the function code, compiler will flag error.
       	void somefunc(const int num){
       	//...
      	++num;//OOPs, by mistake, But compiler will show it as an error
      	//saving your precious time from hunting for the possible bug here 
      	//..
      	}
      Its not necessary to declare an argument being const, but its a good programming style to declare it to be const if you know that this variable won't change value during the execution of that code. It also saves you from changing that variable while coding that function.
    4. Return type of a function as const: Does this means only const objects can be assigned the return value of the this type of function? No, the meaning here is that, the returned value can't be used as an lvalue (i.e. it cannot be used as a target of an assignment). When I read this statement for first time, my very first response was Does it make any sense? Well, if you are returning inbuilt type, then returning as a const doesn't make any difference hence better don't use return by const in this case to avoid any confusion.
      But when you are dealing with pointers or user defined types, then care must be taken regarding this.
    5. Member Functions as const: You have made one class. Someone using this class declare a const instance of this class. What if the user calls a member function on this object which modifies the data inside it? During compile time compiler can't show error on the basis of the steps involved inside the function because functions are already checked for syntax, and now, if compiler see some statement calling that function, it will just match that the argument list passed matches with the signature of that function and if yes, it will insert something like CALL to the location of that function. It will be too much to ask the compiler to check if that function modifies the object. This will also make the compiling process slower, as each time it see some member function called upon some const object, it has to check that the function called doesn't modifies that object. The solution is to make const as the signature of the function which will tell the compiler that this function is not going to change the data members. The compiler won't stop here only. It will check that the function doesn't actually modify the any of data members. And this check has to be done only once, during the compilation of that function. And here it is how you declare const as the signature of the member function:
      	void someclass::func(arguments)const{
      	 //body of function goes here
      	 //.....
      	}
      
      You just add const after the argument list of the function. You can also overload on the basis of this constness i.e., to say, you can define two function with same name and same argument list but one for const objects and other for non-const objects. You must have noticed one such use in Assignment-II, where you have to overload ‘[]’ operator.
    I know, you must haven't been able to digest this concept of constness properly because of my inability to explain them clearly. I will refer this link in case if you will like to learn more in this topic.
    Before closing this point, I will like to give one very important suggestion to you. Whenever you are writing a function, give a thought about its arguments. Does this function should need to modify this value or should use it as it is?(Don't think in term of function implementation but logically.) If you are satisfied it should use the value passed as it is, you should declare it as const in the argument list. Then you should ask yourself, should this function modify any of data member of the object? If not, then declare this member function of type const.
    One interesting topic which I haven't discussed here involves 3 special features of C++: const, passing by reference, and type-conversion. I will try to include this section also sometime later.
  10. Passing by value and Passing by reference:

  11. References are special kind of pointers which are automatically dereferenced. Suppose you declare something like this:
    	int a=10;
    	int& ref2a=a;
    	
    The second line here is declaring a variable 'ref2a' which acts as a reference to the variable 'a' of type int. One important distinction between references and pointers, except automatic dereferenciability, is that references has to be initialized to the object of its reference during the point of its instantiation. Moreover, this reference is binded to this particular object (or variable) for its lifetime.
    The references provides us a very efficient way to pass a variable to a function. Normal routine of passing variables is called passing by value. Passing by value means that a copy of that object is going to be made by the function, which in case of sizable objects may be performance issue. Most of the time this copying is unnecessary. This copying is desirable if the function makes some changes to the object which should not be reflected outside. But for majority cases, just object is required for reading purpose. One way to avoid the copying would be to pass a pointer to the variable. But in that case, whenever u want to read the data, u have to use dereferencing operator, which doesn't looks clean. With references used to pass the variable, you do not have to dereference them (remember, references are automatically dereferenciated). Hence, while writing your function, you get the illusion as if you are working directly with the variable. Redundant to say that passing of reference will not involve copying of original object.
    The word of caution; if you make any change to the variable passed by reference inside the function, it will be reflected outside. If this is what you want, then its fine.
    Sometimes you will like your function to return more than one variable. But this is not possible. In that case, you can pass some variables as references, and inside function use them to write the result. There is one more advantage here. When a function returns an object, a copy is actually returned. The local copy is destroyed inside function. But when you are using reference object to write result, this copying is avoided. Sure enough, this way of passing variables to function for getting result doesn't look nice.
    Note 1: New compilers have features of return value optimization to avoid unnecessary copying while returning the result. More information can be found through googling.
    Note 2: I have noticed that recent compilers are smart enough to avoid this copying. Though in your function you return an object, the compiler optimizes to use this object directly outside the function scope (and doesn't destroy it).