Tuesday, 23 October 2012

This Pointer, Friends, and Static Functions Structure

This Pointer
Unit 2 This Pointer, Friends, and Static Functions
Structure
2.1 Introduction
2.2 The this Pointer
2.3 Friends
2.3.1 Friend Functions
2.3.2 Friend Classes
2.3.3 Friend Scope
Self Assessment Questions
2.4 Static Functions
2.5 Summary
2.6 Terminal Questions
References and Further Reading
2.1 Introduction
This chapter with some of the very important and handy features of C++, such as, the this pointer, friend functions, and static functions.
Objectives
At the end of this chapter that contains certain miscellaneous yet important features of C++ you will be able to:
· Understand what this pointer is, and also the purpose of this pointer.
· Understand friends, its advantages, and scope considerations.
· Understand static functions.
· Use the features described in this unit in your programs.
2.2 The this Pointer
The this pointer is used as a pointer to the class object instance by the member function. The address of the class instance is passed as an implicit parameter to the member functions. The sample below, in this section shows how to use it. It is common knowledge that C++ keeps only one copy of each member function and the data members are allocated memory for all of their instances. This kind of various instances of data is maintained using this pointer. Look at the sample below.
The following are the features of this pointer:
· this pointer stores the address of the class instance, to enable pointer access of the members to the member functions of the class.
· this pointer is not counted for calculating the size of the object.
· this pointers are not accessible for static member functions.
· this pointers are not modifiable. 
Look at the following example to understand how to use the 'this' pointer:
class this_pointer_example { // class for explaining C++ tutorial
int data1;
    public:
//Function using this pointer for C++ Tutorial
int getdata() {
        return this->data1;
}
//Function without using this pointer
      void setdata(int newval) {
data1 = newval;
}
};
Thus, a member function can gain the access of data member by either using this pointer or not.
2.3 Friends
Friend classes in C++ give us access to non-member functions or other classes. By using the friend keyword, a class can grant access to non-member functions or to another class. These friend functions and friend classes are permitted to access private and protected class members. There are places where friends can lead to more intuitive code, and are often needed to correctly implement operator overloading.
If encountering friend functions for the first time, you might feel slightly uneasy since they seem to violate encapsulation. This feeling may stem from the fact that a friend function is not strictly a member of the class. By thinking of a friend function as part of the class’s public interface, you can get a better understanding of how friends work. From a design perspective, friends can be treated in a similar way to public member functions. The concept of a class interface can be extended from public members to include friend functions and friend classes. Put another way: Friend functions do not break encapsulation; instead they naturally extend the encapsulation barrier.
2.3.1 Friend Functions
Friend functions can be declared anywhere within a class declaration, but it is common practice to list friends at the beginning of the class. The public and protected keywords do not apply to friend functions, as the class has no control over the scope of friends.
If we want to declare an external function as friend of a class, thus allowing this function to have access to the private and protected members of this class, we do it by declaring a prototype of this external function within the class, and preceding it with the keyword friend:
// friend functions
#include <iostream>
using namespace std;
class CRectangle {
    int width, height;
  public:
      void set_values (int, int);
      int area () {return (width * height);}
      friend CRectangle duplicate (CRectangle);
};
void CRectangle::set_values (int a, int b) {
    width = a;
    height = b;
}
CRectangle duplicate (CRectangle rectparam) {
    CRectangle rectres;
    rectres.width = rectparam.width*2;
    rectres.height = rectparam.height*2;
    return (rectres);
}
int main () {
    CRectangle rect, rectb;
    rect.set_values (2,3);
    rectb = duplicate (rect);
    cout << rectb.area();
    return 0;
}
The duplicate function is a friend of CRectangle. From within that function we have been able to access the members width and height of different objects of type CRectangle, which are private members. Notice that neither in the declaration of duplicate() nor in its later use in main() have we considered duplicate a member of class CRectangle. It isn't! It simply has access to its private and protected members without being a member.
The friend functions can serve, for example, to conduct operations between two different classes. Generally, the use of friend functions is out of an object-oriented programming methodology, so whenever possible it is better to use members of the same class to perform operations with them. Such as in the previous example, it would have been shorter to integrate duplicate() within the class CRectangle.
2.3.2 Friend Classes
As well as choosing a non-member friend function, a class has two other possibilities for its friends. A class can declare a member function of another class as a friend, or declare another class as a friend class.
Friend classes are used in cases where one class is tightly coupled to another class. For example, suppose we have a class CPoint that represents a coordinate, and a class CPointCollection that holds a list of points. Since the collection class may need to manipulate point objects, we could declare CPointCollection as a friend of the CPoint class:
// Forward declaration of friend class.
class CPointCollection;
// Point class.
class CPoint {
friend CPointCollection;
private:
double m_x;
double m_y;
public:
CPoint(const double x, const double y) :
m_x(x),
m_y(y) { }
~CPoint(void) { }
// ...
};
Since the collection class is a friend of CPoint, it has access to the internal data of any point object. This is useful when individual elements of the collection need to be manipulated. For example, a set method of the CPointCollection class could set all CPoint elements to a particular value (vector is a STL container which is discussed in detail in Chapter 8):
class CPointCollection {
private:
vector<CPoint> m_vecPoints;
public:
CPointCollection(const int nSize) :
m_vecPoints(nSize) { }
~CPointCollection(void);
void set(const double x, const double y);
// ...
};
The set member can iterate over the collection and reset each point:
void CPointCollection::set(const double x, const double y) {
// Get the number of elements in the collection.
const int nElements = m_vecPoints.size();
// Set each element.
for(int i=0; i<nElements; i++) {
m_vecPoints[i].m_x = x;
m_vecPoints[i].m_y = y;
}
}
One thing worth noting about friend classes is that friendship is not mutual: although CPointCollection can access CPoint, the converse is not true. Friendship is also not something that is passed down a class hierarchy. Derived classes of CPointCollection will not be able to access CPoint. The principle behind this is that friendship is not implicitly granted; each class must explicitly choose its friends.
2.3.3 Friend Scope
The name of a friend function or class first introduced in a friend declaration is not in the scope of the class granting friendship (also called the enclosing class) and is not a member of the class granting friendship.
The name of a function first introduced in a friend declaration is in the scope of the first nonclass scope that contains the enclosing class. The body of a function provided in a friend declaration is handled in the same way as a member function defined within a class. Processing of the definition does not start until the end of the outermost enclosing class. In addition, unqualified names in the body of the function definition are searched for starting from the class containing the function definition.
If the name of a friend class has been introduced before the friend declaration, the compiler searches for a class name that matches the name of the friend class beginning at the scope of the friend declaration. If the declaration of a nested class is followed by the declaration of a friend class with the same name, the nested class is a friend of the enclosing class.
The scope of a friend class name is the first nonclass enclosing scope. For example:
class A {
    class B { // arbitrary nested class definitions
        friend class C;
    };
};
is equivalent to:
class C;
class A {
   class B { // arbitrary nested class definitions
      friend class C;
   };
};
If the friend function is a member of another class, you need to use the scope resolution operator (::). For example:
class A {
    public:
        int f() { }
};
class B {
    friend int A::f();
};
Friends of a base class are not inherited by any classes derived from that base class. The following example demonstrates this:
class A {
    friend class B;
    int a;
};
class B { };
class C : public B {
    void f(A* p) {
        //p->a = 2;
    }
};
The compiler would not allow the statement p->a = 2 because class C is not a friend of class A, although C inherits from a friend of A.
Friendship is not transitive. The following example demonstrates this:
class A {
    friend class B;
    int a;
};
class B {
    friend class C;
};
class C {
    void f(A* p) {
        //p->a = 2;
    }
};
The compiler would not allow the statement p->a = 2 because class C is not a friend of class A, although C is a friend of a friend of A.
If you declare a friend in a local class, and the friend's name is unqualified, the compiler will look for the name only within the innermost enclosing nonclass scope. You must declare a function before declaring it as a friend of a local scope. You do not have to do so with classes. However, a declaration of a friend class will hide a class in an enclosing scope with the same name. The following example demonstrates this:
class X { };
void a();
void f() {
    class Y { };
    void b();
    class A {
        friend class X;
        friend class Y;
        friend class Z;
        //friend void a();
        friend void b();
        //friend void c();
    };
    ::X moocow;
    //X moocow2;
}
In the above example, the compiler will allow the following statements:
· friend class X: This statement does not declare ::X as a friend of A, but the local class X as a friend, even though this class is not otherwise declared.
· friend class Y: Local class Y has been declared in the scope of f().
· friend class Z: This statement declares the local class Z as a friend of A even though Z is not otherwise declared.
· friend void b(): Function b() has been declared in the scope of f().
· ::X moocow: This declaration creates an object of the nonlocal class ::X.
The compiler would not allow the following statements:
· friend void a(): This statement does not consider function a() declared in namespace scope. Since function a() has not been declared in the scope of f(), the compiler would not allow this statement.
· friend void c(): Since function c() has not been declared in the scope of f(), the compiler would not allow this statement.
· X moocow2: This declaration tries to create an object of the local class X, not the nonlocal class ::X. Since local class X has not been defined, the compiler would not allow this statement.
Self Assessment Questions
1. Name the types of friends that can be found in C++.
2. Implement the examples provided in this section and observe the results.
2.4 Static Functions
Static data types can be accessed without instantiation of the class in C++. This is applicable for static functions also.
The differences between a static member function and non-static member functions are as follows:
· A static member function can access only static member data, static member functions and data and functions outside the class. A non-static member function can access all of the above including the static data member.
· A static member function can be called, even when a class is not instantiated, a non-static member function can be called only after instantiating the class as an object.
· A static member function cannot be declared virtual, whereas a non-static member functions can be declared as virtual
· A static member function cannot have access to the 'this' pointer of the class.
· The static member functions are not used very frequently in programs. But nevertheless, they become useful whenever we need to have functions which are accessible even when the class is not instantiated.
You cannot have static and non-static member functions with the same names and the same number and type of arguments.
Like static data members, you may access a static member function f() of a class A without using an object of class A.
A static member function does not have a this pointer. The following example demonstrates this:
#include <iostream>
using namespace std;
struct X {
    private:
        int i;
        static int si;
    public:
        void set_i(int arg) { i = arg; }
        static void set_si(int arg) { si = arg; }

        void print_i() {
        cout << "Value of i = " << i << endl;
        cout << "Again, value of i = " << this->i << endl;
    }
    static void print_si() {
        cout << "Value of si = " << si << endl;
        //cout << "Again, value of si = " << this->si << endl;
    }
};
int X::si = 77; //Initialize static data member
int main() {
    X xobj;
    xobj.set_i(11);
    xobj.print_i();
    //static data members and functions belong to the class and
    //can be accessed without using an object of class X
    X::print_si();
    X::set_si(22);
    X::print_si();
}
Output:
Value of i = 11
Again, value of i = 11
Value of si = 77
Value of si = 22
The compiler does not allow the member access operation this->si in function A::print_si() because this member function has been declared as static, and therefore does not have a this pointer.
You can call a static member function using this pointer of a non-static member function. In the following example, the non-static member function printall() calls the static member function f() using this pointer:
#include <iostream>
using namespace std;
class C {
    static void f() {
        cout << "Here is i: " << i << endl;
    }
    static int i;
    int j;
    public:
        C(int firstj): j(firstj) { }
        void printall();
};
void C::printall() {
    cout << "Here is j: " << this->j << endl;
    this->f();
}
int C::i = 3;
int main() {
    C obj_C(0);
    obj_C.printall();
}
Output:
Here is j: 0
Here is i: 3
A static member function cannot be declared with the keywords virtual, const, volatile, or const volatile.
A static member function can access only the names of static members, enumerators, and nested types of the class in which it is declared. Suppose a static member function f() is a member of class X. The static member function f() cannot access the non-static members X or the non-static members of a base class of X.
2.5 Summary
Friend functions and friend classes allow a class interface to be extended in a natural and efficient way. For some problems, friend functions lead to more intuitive code, while friend classes are needed when two classes are tightly coupled. Non-member friend functions are especially useful for implementing operator overloading, a good example being operator<<.
Friend functions do not break encapsulation, but rather enhance a class interface. Although this is the case, friends should be used judiciously; a member function will often do just as well. As a general rule of thumb, use member functions where possible, and friends where necessary. A well-designed project will not be free of friend functions, but will instead use them in places where non-members are naturally part of a class.
This chapter also discussed the use of this pointer. This chapter has also discussed static functions.
2.6 Terminal Questions
1. What is this pointer?
2. How is this pointer helpful?
3. Describe friend functions and friend classes.
4. Outline the differences between static member functions and non-static member functions.
5. A static member function does not have a this pointer. Is the previous sentence true or false?
6. Point out the keywords that may not be suffixed with static member functions.

No comments:

Post a Comment

Post a Comment