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

C++ Programming Tutorial III

Arrays, Pointers, References


Arrays of Objects


#include <iostream.h>

class c1 {
    int i;
public:
    cl(int j) {i=j;}    // constructor
    int get_i() {return i;}
};

main()
{
    cl ob[3] = {1, 2, 3};    // initializers
    int i;

    for (i=0; i<3; i++) {
        cout << ob[i].get_i() << "\n";

    return 0;
}


  • The syntax for declaring and using an object array is exactly the same as it is for any other type of variable.

  • If a parameterized constructor is used, you can initialize each object in an array by specifying an initialization list.

  • Exercise: Check the syntax to initialize an object array if the constructor requires multiple parameters.



Pointers to Objects


#include  <iostream.h>

class cl {
    int i;
public:
    cl(int j) {i=j;}
    int get_i() {return i;}
};

main()
{
    cl ob(88), *p;

    p = &ob;     // get address of ob

    cout << p->get_i();     // use -> to call get_i()

    return 0;
}


  • When accessing members of a class given a pointer to an object, use the arrow (->) operator.



Pointers to Object Members


#include <iostream.h>

class cl {
public:
    int i;
    cl (int j) {i=j;}
};

main()
{
    cl ob(1);
    int *p;

    p = &ob.i;     // get address of ob.i

    cout << *p;    // access ob.i via p

    return 0;
}


  • You can assign the address of a public member of an object to a pointer.

  • Then access that member by using the pointer.



The this Pointer


#include <iostream.h>

class pwr {
    double b;
    int e;
    double val;
public:
    pwr (double base, int exp);
    double get_pwr() {return val;}
};

pwr::pwr (double base, int exp)
{
    b = base;
    e = exp;
    val = 1;
    if (exp==0) return;
    for ( ; exp>0; exp--) 
        val = val * b;
}

main()
{
    pwr x(4.0, 2), y(2.5, 1), z(5.7,0);

    cout << x.get_pwr() << " ";
    cout << y.get_pwr() << " ";
    cout << z.get_pwr() << "\n";

    return 0;
}

Alternative:

pwr::pwr(double base, int exp)
{
    this->b = base;
    this->e = exp;
    this->val = 1;
    if (exp==0) return;
    for ( ; exp>0; exp--) 
        this->val = this->val * this->b;
}


  • When a member function is called, it is automatically passed an implicit argument that is a pointer to the corresponding object instance.

  • "this" pointer is very important when operators are overloaded; and

  • Whenever a member function must utilize a pointer to the object that invoked it.



References


C's Approach:

#include <iostream.h>

void neg (int *i);

main()
{
   int x;
    
   x = 10;
   cout << x << " negated is ";

   neg(&x);
   cout << x << "\n";

   return 0;
}

void neg (int *i)
{
   *i = -*i;
}

C++'s Approach:

#include <iostream.h>

void neg(int &i);    // i now a reference

main()
{
   int x;

   x = 10;
   cout << x << " negated is ";

   neg(x);   // no longer need the & operator
   cout << x << "\n";

   return 0;
}

void neg(int &i)
{
   i = -i;   // i is now a reference, don't need *
}


  • In C, to create a call-by-reference, you must explicitly pass the address of an argument to the function.

  • In C++, call-by-reference can be done automatically by using reference parameters.

  • To create a reference parameter, precede the parameter's name with an &.

  • The reference parameter automatically refers to (implicitly points to) the argument used to call the function.



Passing References to Objects


#include <iostream.h>

class cl {
    int id;
public:
    int i;
    cl(int i);    
    ~cl();
    void neg(cl &o) {o.i = -o.i;}  // no temporary created
};

cl::cl(int num)
{
    cout << "Constructing " << num << "\n";
    id = num;
}

cl::~cl()
{
    cout << "Destructing " << id << "\n";
}

main()
{
    cl o(1);

    o.i = 10;
    o.neg(o);

    cout << o.i << "\n";

    return 0;
}

Output:

Constructing 1
-10
Destructing 1


  • Recall:
    • When an object is passed as an argument to a function, a copy of that object is made.

    • Constructor is not called.

    • When the function terminates, the destructor is called for the copy.

  • When you pass an object by reference, no copy of the object is made.

  • Thus, no object is destroyed and no destructor is called when the function terminates.



Returning References


#include <iostream.h>

char &replace(int i);    // return a reference

char s[80] = "Hello There";

main()
{
    replace(5) = 'X';    // assign X to space after Hello

    cout << s;

    return 0;
}

char &replace(int i)
{
    return s[i];
}


  • A function may return a reference.

  • This has the rather startling effect of allowing a function to be used on the left side of an assignment statement.



C's Dynamic Allocation


struct node {
    int data;
    struct node *left;
    struct node *right;
}

...

main()
{
    struct node *p;

    ...
    p = (struct node *) malloc (sizeof(struct node));

    ...
    free(p);
    
    ...
}


  • In C, dynamic memory allocation is achieved by using malloc() and free().



C++'s Dynamic Allocation


#include <iostream.h>
#include <stdlib.h>

main()
{
    int *p;

    p = new int (87);    // initialize to 87
    
    if (!p) {
        cout << "Allocation error\n";
        exit(1);
    }

    cout << "At " << p << " ";
    cout << "is the value " << *p << "\n";

    delete p;

    return 0;
}


  • The new operator returns a pointer to allocated memory (from the heap).

        p_var = new type (initializer);
        
  • You can initialize the allocated memory to some known value by using an initializer.

  • Advantages:

    • Size is computed automatically.

    • No need for explict type cast.

    • new and delete can be overloaded.

  • Question: Can complex data types be initialized?

  • The delete operator frees memory.



Allocating Objects


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

class balance {
    double cur_bal;
    char name[80];
public:
    void set(double n, char *s) {
        cur_bal = n;
        strcpy(name, s);
    }

    void get_bal(double &n, char *s) {
        n = cur_bal;
        strcpy (s, name);
    }
};
main()
{
    balance *p;
    char s[80];
    double n;

    p = new balance;
    if (!p) {
        cout << "Allocation error\n";
    exit(1);
    }

    p->set(12387.87, "Ralph Wilson");

    p->get_bal(n, s);

    cout << s << "'s balance is: " << n;
    cout << "\n";

    delete p;

    return 0;
}


  • You can allocate objects dynamically by using new.

  • When an object is created (using new), its constructor function (if it has one) is called.

  • When the object is freed, its destructor function is called.

  • You can allocate arrays of objects. However, since no array allocated by new can have an initializer, you must sure that a parameterless constructor is provided with the class declaration.


End of Tutorial III


 

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