ÄúµÄλÖãºÑ°ÃÎÍøÊ×Ò³£¾±à³ÌÀÖÔ°£¾C/C++±à³Ì£¾Tutorial of C++

C++ Programming Tutorial II

Classes and Objects


Classes


class class-name {
     private data and functions 
access-specifier:
     data and functions
access-specifier:
     data and functions
...
...
...
access-specifier:
     data and functions
} object-list;
class employee {
   char         name[80];
   double       wage;

public:
   void putname (char *n);
   void getname (char *n);
   void putwage (double w);
   double getwage();
};


  • A class is a logical abstraction, but an object has physical existence.

  • access-specifier can be:

    • public:

      Allow functions or data to be accessible to other parts of the program.

    • private:

      May be accessed only by other members of the class.

    • protected:

      Used when inheritance is involved; discussed later.

Friend Functions


#include  <iostream.h>

class myclass {
     int  a, b;
public:
     friend int sum(myclass x);
     void set_ab(int i, int j);
};

void myclass::set_ab (int i, int j)
{
     a = i;
     b = j;
}

// Note: sum() is not a member function of any class.
int sum (myclass x)
{
     /* Because sum() is a friend of myclass, it can
        directly access a and b. */

     return x.a + x.b;
}
main()
{
     myclass n;

     n.set_ab (3, 4);
    
     cout << sum(n);
 
     return 0;
}


  • A friend function has access to all private and protected (and public of course) members of the class for which it is a friend.


#include   <iostream.h>

#define IDLE   0
#define INUSE  1

class C2;     // forward declaration

class C1 {
     int status; // IDLE if off; INUSE if on screen
public:
     void set_status(int state);
     friend int idle(C1 a, C2 b);
};


class C2 {
     int status; // IDLE if off; INUSE if on screen
public:
     void set_status(int state);
     friend int idle(C1 a, C2 b);
};


void C1::set_status (int state)
{
     status = state;
}


void C2::set_status (int state)
{
     status = state;
}


int idle (C1 a, C2 b)
{
     if (a.status || b.status)
    return 0;
     else
    return 1;
}
main()
{
     C1 x;
     C2 y;

     x.set_status(IDLE);
     y.set_status(IDLE);
 
     if (idle(x, y))
    cout << "Screen can be used.\n";
     else
    cout << "In use.\n";

     x.set_status(INUSE);

     if (idle(x, y)) 
    cout << "Screen can be used.\n";
     else
    cout << "In use.\n";

     return 0;
}


  • Two or more classes may contain members that are interrelated relative to other parts of a program.

  • One function (idle()) is called, instead of two (C1::get_status() and C2::get_status()), thus more efficient.



Friend Classes


#include   <iostream.h>

class coins {
   // The following is a private enumeration
   enum units {penny, nickel, dime, quarter, half_dollar};
   friend class amount;
}


class amount {
   coins::units money;  // notice use of coins::units
public:
   void setm();
   int getm();
} ob;


void amount::setm()
{
   // Enumeration units accessible here because
   // amout is friend of coins.
   money = coins::dime;
}


int amount::getm()
{
   return money;
}


main()
{
   ob.setm();

   cout << ob.getm();  // outputs the number 2

   return 0;
}


  • A friend class has access to the private names defined within the other class.

  • When one class is a friend of another, it only has access to names defined within the other class, i.e. it does not inherit the other class.



Inline Functions


#include   <iostream.h>


inline int max(int a , int b)
{
    return a>b ? a : b;
}


main()
{
    cout << max(10, 20);
    cout << " " << max(99, 88);

    return 0;
}

#include   <iostream.h>


main()
{
   cout << (10 > 20 ? 10 : 20);
   cout << " " << (99 > 88 ? 99 : 88);

   return 0;
}


  • Inline functions are short functions that are not actually called; rather, their code is expanded inline at the point of each invocation.

  • Although expanding function calls inline can produce faster run times, it also often results in larger code size because of the duplicated code.

  • The compiler can choose to ignore the inline specification.




#include   <iostream.h>


class myclass {
    int a, b;
public:
    void init(int i, int j);
    void show();
};


inline void myclass::init (int i, int j)
{
    a = i;
    b = j;
}


inline void myclass::show()
{
    cout << a << " " << b << "\n";
}


main()
{
    myclass x;
  
    x.init (10, 20);
    x.show();

    return 0;
}


  • Class member functions can also be inline.




#include   <iostream.h>


class myclass {
    int a, b;
public:
    // automatic inline
    void init(int i, int j) {a=i; b=j;}
    void show() {cout << a << " " << b << "\n";}
};


main()
{
    myclass x;
  
    x.init (10, 20);
    x.show();

    return 0;
}


  • Define short functions within a class declaration.

  • Automatically made into inline.



Parameterized Constructors


#include   <iostream.h>
#include  <string.h>

#define   IN 1
#define   CHECKED_OUT 0

class book {
    char author[40];
    char title[40];
    int  status;
public:
    book (char *n, char *t, int s);
    int get_status() {return status;}
    void set_status(int s) {status = s;}
    void show();
};


book::book (char *n, char *t, int s)
{
    strcpy (author, n);
    strcpy (title, t);
    status = s;
}


void book::show()
{
    cout << title << " by " << author;
    cout << " is ";
    if (status==IN) 
    cout << "in.\n";
    else
    cout << "out.\n";
}


main()
{
    book b1 ("Twain", "Tom Sawyer", IN);
    book b2 ("Melville", "Moby Dick", CHECKED_OUT);

    b1.show();
    b2.show();

    return 0;
}


  • Pass arguments to constructor functions.

  • Typically used to initialize an object when it is created.



Static Data members


#include   <iostream.h>


class shared {
     static int a;
     int b;
public:
     void set(int i, int j) {a=i; b=j;}
     void show();
};


int shared::a;     // define a; thus allocate memory


void shared::show() 
{
     cout << "This is static a: " << a;
     cout << "\nThis is non-static b: " << b;
     cout << "\n";
}


main()
{
     shared x, y;

     x.set(1, 1);   // set a to 1
     x.show();

     y.set(2, 2);   // change a to 2
     y.show();

     x.show();      /* Here, a has been changed for both x and y
                       because a is shared by both objects. */

     return 0;
}

Output:

This is static a: 1
This is non-static b: 1
This is static a: 2
This is non-static b: 2
This is static a: 2
This is non-static b: 1


  • Only one copy of a static data member exists.

  • All objects of the class will share that variable.

  • A static data member exists before any object of its class is created.




#include   <iostream.h>


class client {
     static int resource;
public:
     int get_resource();
     void free_resource() {resource = 0;}
};


int client::resource;     // define resource


int client::get_resource()
{
     if (resource) 
    return 0;    // resource already in use
     else {
    resource = 1;
    return 1;    // resource allocated to this object
     }
}


main()
{
     client  ob1, ob2;

     if (ob1.get_resource()) 
    cout << "ob1 has resource \n";
     
     if (!ob2.get_resource())
    cout << "ob2 denied resource \n";

     ob1.free_resource();     // let someone else use it

     if (ob2.get_resource())
    cout << "ob2 can now use resource\n";

     return 0;
}


  • One of the most common uses of static member variables is to provide access control to some shared resources.

  • By using static member variables, any need for global variables is virtually eliminated.



Static member functions


#include   <iostream.h>


class client {
     static int resource;
public:
     static int get_resource();
     void free_resource() {resource = 0;}
};


int client::resource;     // define resource


int client::get_resource()
{
     if (resource) 
    return 0;    // resource already in use
     else {
    resource = 1;
    return 1;    // resource allocated to this object
     }
}


main()
{
     client  ob1, ob2;

     /* get_resource() is static, so may be called independent
        of any object */

     if (client::get_resource())
    cout << "resource has been acquired\n";

     if (!client::get_resource())
    cout << "resource in use\n");

     ob1.free_resource();

     if (ob2.get_resource())    // can still call using object syntax
    cout << "ob2 can now use resource\n";

     return 0;
}


  • Static member functions can only access other static members of the class.

  • A static member function can be called directly, independent of any object instance, using the class name and the scope resolution operator.

  • Of course, can still be called in connection with an object instance.

  • Can be used to "preinitialize" private static data before any object is actually created.



Passing objects to functions


#include   <iostream.h>


class myclass {
     int i;
public:
     myclass (int n);
     ~myclass ();
     void set_i(int n) {i=n;}
     int get_i() {return i;}
};


myclass::myclass (int n)
{
     i = n;
     cout << "Constructing " << i << "\n";
}


myclass::~myclass()
{
     cout << "Destroying " << i << "\n";
}


void f(myclass ob);
main()
{
     myclass o(1);

     f(o);
     cout << "This is i in main: ";
     cout << o.get_i() << "\n";

     return 0;
}


void f(myclass ob)
{
     ob.set_i(2);

     cout << "This is local i: " << ob.get_i();
     cout << "\n";
}

Output:

Constructing 1
This is local i: 2
Destroying 2
This is i in main: 1
Destroying 1


  • Objects are passed to functions through the use of the standard call-by-value mechanism.

  • That is, a copy of an object is made when it is passed to a function.

  • Question: Should constructor and destructor called for the object copy?

  • Constructor is not executed when the copy of the object is generated in a function call.

  • Destructor is executed when the copy is destroyed.


Object Assignment


#include   <iostream.h>


class myclass {
     int i;
public: 
     void set_i(int n) {i=n;}
     int get_i() {return i;}
};


main()
{
     myclass ob1, ob2;

     ob1.set_i(99);
     ob2 = ob1;    // assign data from ob1 to ob2

     cout << "This is ob2's i: " << ob2.get_i();

     return 0;
}


  • You can assign one object to another of the same class.

  • This causes the data of the object on the right side to be copied into the data of the object on the left.

  • Bit-by-bit copy is used.


End of Tutorial II


 

[ tutorial 1(a)| tutorial 1(b)| tutorial 2| tutorial 3| tutorial 4]