Docstoc

abstraction

Document Sample
abstraction Powered By Docstoc
					        Comp151



          C++:

Data Abstraction & Classes
                                       [comp151]   1
Outline


 • Data abstraction
 • Data members and member functions
 • Information hiding
                                                         [comp151]   2
A Brief History of C++


 • Bjarne Stroustrup of AT&T Bell Labs extends C with Simula-like
   classes in the early 1980s, and the new language was called ”C
   with Classes”.
 • C++, the successor of ”C with Classes”, was designed by Strous-
   trup in 1986, and version 2.0 was introduced in 1989.


The design of C++ was guided by the following three principles:

1. The use of classes would not result in programs executing any
   more slowly than programs not using classes.
2. C programs should run as a subset of C++ programs.
3. No run-time inefficiency should be added to the language.
                                                          [comp151]   3
Data Abstraction


 • What is a “chair”?

 • What is a “stack”?



A data abstraction is a simplified view of an object that includes
only features one is interested in while hides away the unnecessary
details.
In programming languages, a data abstraction becomes an
abstract data type or a user-defined type.
In OOP, it is implemented as a class.
                                           [comp151]   4
Example: Implement a Stack with an Array



       1        data
       2

       3
size




                top
Example: Implement a Stack with a Linked List[comp151]   5




     top


      -999




     top
                              (latest item)

      -999            1             2
                                                           [comp151]   6
Information Hiding


 • An abstract specification tells us the behavior of an object inde-
   pendent of its implementation. i.e. It tells us what an object
   does independent of how it works.
 • Information hiding is also known as data encapsulation, or
   representation independence.

 • The principle of information hiding:
   Design a program so that the implementation of an object can
   be changed without affecting the rest of the program.
   e.g. Changing the implementation of a stack from an array to a
   linked list has no effect on users’ programs.
                                                                                  [comp151]   7
Example: stack ar.h

                 class Stack                     data memebers
                 {
                      private:
                        int size;                      // max. size of storage
                        Object* top;                   // point to the next available space
access control          Object* data;                  // data storage

                      public:
                        Stack( int N);                 // a constructor
                        ~Stack();                      // destructor

                        // basic operations
                        void push(const Object& x );   // add another datum
                        Object pop( );                 // get the most recent datum

                        // status operations
                         int num_elements( ) const;
                        bool empty( ) const;
                        bool full( ) const;                        member functions
                                                                   (public interface)
                 };
                                                            [comp151]   8
Structure vs. Class

In C++, structures are special classes and they can have member
functions:
struct Stack                                    // a stack of integers
{
   int size; int∗ top; int∗ data;

     Stack(int N);
     void push(int x);
     int pop();
};

By default,
struct { . . . }; = class { public: . . . };
class { . . . }; = struct { private: . . . };
                                                          [comp151]   9
Class Name: Name Equivalence

A class definition introduces a new abstract data type. C++ relies
on name equivalence (and NOT structure equivalence) for class
types.
class    X { int a; };
class    Y { int a; };
class    W { int a; };
class    W { int a; };                    // error, double definition

X x;
Y y;

x = y;                                      // error: type mismatch
                                                             [comp151]   10
Class Data Members

Data members can be any basic type, or any user-defined types if
they are already “seen” except:

 • A class name can be used in its own definition for its pointers:
  class Cell { int info; Cell *next; . . . };
 • A forward declaration for class pointers:
  class Cell;                                     // forward declaration
  class Stack
  {
      int size;
      Cell∗ top;         // points to an object with forward declaration
      Cell x;                                // Error: Cell not defined!
  };
                                                               [comp151]   11
Class Data Members ..

But, they can NOT be initialized inside the class definition.
class Stack
{ ...
    int∗ top = 0;   // Error: class data member cannot be initialized here
};

Initialization should be done with appropriate constructors, or mem-
ber functions.
                                                           [comp151]   12
Class Member Functions

These are the functions declared inside the body of a class; but they
can be defined in two ways:


 • within the class body, in which case, they are inline functions.
   class Stack
   { ...
       void push(int x) { ∗top = x; ++top; }
       int pop() { --top; return (∗top); }
   };
                                                         [comp151]   13
Class Member Functions ..


 • outside the class body (any benefits of doing this?)
  class Stack
  { ...
      void push(int x);
      int pop();
  };

  void Stack::push(int x) { ∗top = x; ++top; }
  int Stack::pop() { --top; return (∗top); }


Question: Can we add data and function declarations to a class
after the end of the class definition?
                                                            [comp151]   14
Inline Functions


 • Function calls are expensive because when a function is called,
   the operating system has to do a lot of things behind the scene
   to make that happens.
  int f(int x) { return 4∗x∗x + 9∗x + 1; }

  int main() { int y = f(5); }


 • For small functions that are called frequently, it is actually more
   efficient to unfold the function codes at the expense of program
   size (both source file and executable).
  int main() { int y = 4∗5∗5 + 9∗5 + 1; }
                                                           [comp151]   15
Inline Functions ..


 • But functions has the benefit of easy reading, easy maintenace,
   and type checking by the compiler.
 • In C++, you have the benefits of both by declaring the function
   inline.
  inline int f(int x) { return 4∗x∗x + 9∗x + 1; }

  int main() { int y = f(5); }


 • In C++, when you defined a member function inside the class,
   it is treated as an inline function.
 • However, C++ compilers may NOT honor your inline decla-
   ration. i.e. The inline declaration is just a hint to the compiler
   which still has the freedom to choose whether to inline your
   function or not, especially when it is large!
                                                                 [comp151]   16
Inline Class Member Functions

While member functions can be defined inside the class body and
are automatically treated as inline functions, to enhance readability,
one may also define them outside a class definition but usually in
the same include file as follows:

   // stack1.h                         // stack2.h

   class Stack                         class Stack
   {                                   {
       ...                                 ...
       inline void push(int x)             inline void push(int x);
       {                               };
            ∗top = x; ++top;
       }                               inline void Stack::push(int x)
   };                                  {
                                            ∗top = x; ++top;
                                       }
                                                            [comp151]   17
Member Access Control

A member of a class can be:

public : accessible to anybody

private : accessible only to member functions and friends of the
  class. ⇒ Enforce information hiding

protected : accessible to member functions and friends of the
  class, as well as to member functions and friends of its derived classes
  (subclasses).
                                              [comp151]   18
Example: Member Access Control


class Stack
{
   private:
     Cell∗ top;
   public:
     int size;
   ...
};

int main()
{
    Stack x;
    cout     x.size;               // OK: size is public
    x.push(2);                   // OK: push() is public
    cout     x.top→info;    // ERROR: cannot access top
}
                                                                [comp151]   19
How Are Objects Implemented?


                                            Stack x:   size
    • Each class object gets its own                    top
                                                       data
      copy of the class data members.       Stack y:   size
                                                        top
    • All objects of the same class share              data

      one copy of the member functions.
int main()
{
    Stack x(2), y(3);
                                                       push()
      x.push(1);                                       pop()
      y.push(2);
      y.pop();
}
                                                           [comp151]   20
This Pointer


 • Each class member function implicitly contains a pointer of its
   class type named “this”.
 • When an object calls the function, this pointer is set to point to
   the object.
 • For example, the C++ compiler developed by AT & T Bell Labs
   will translate Stack::push(int x) function in the Stack class to a
   unique global function by adding a new argument:

  void Stack::push(Stack∗ this, int x)
  {
      ∗this→top = x;
      ++this→top;
  }

 • a.push(x) becomes push(&a, x).
                                                           [comp151]   21
Example: Return an Object by (*this)


class Complex
{
  private:
    float real;
    float imag;

     public:
       Complex add(const Complex& x)   // Addition of complex numbers
       {
           real += x.real;
           imag += x.imag;
           return ∗this;
       }
};
                                                         [comp151]   22
Class Scope and Scope Operator ::

C++ uses lexical (static) scope rules: the binding of name occur-
rences to declarations are done statically at compile time.
int height;

class Weird
{
    short height;
    Weird() { height = 0; }
};

Quiz #1: Which “height” is used in Weird::Weird()?

Quiz #2: Can we access the global one in a class body?
                                                          [comp151]   23
Class Object Initialization

If ALL data members of the class are public, they can be initialized
when they are created as follows:
class Word
{
   public:
     int frequency;
     char∗ str;
};

int main() { Word movie = {1, "Titantic"}; }
                                                    [comp151]   24
Class Object Initialization ..

What happens if some of data members are private?
class Word
{
     char∗ str;
   public:
     int frequency;
};

int main() { Word movie = {1, "Titantic"}; }

Error: a.cc:8: ‘movie’ must be initialized by
               constructor, not by ‘{...}’
                                                    [comp151]   25
What you should take from this lecture


 • Data abstraction: class
 • Information hiding
   – class vs struct
   – Access control specifiers: private, protected, public
   – scope
 • the use of inline functions
 • this pointer
     Comp151



Separate Compilation
                                                         [comp151]   26
Motivation: “Divided We Win”

We have a program “program.cpp” that uses a class called Picture
to manipulate “character pictures”: you may frame them, and hor-
izontally or vertically glue them together.
It is useful to keep the implementation of the Picture class in a
separate file “picture.cpp”, because:

 • We can easily reuse it in another (application) program
 • Two programmers can work easily together: one implements
   Picture and the other writes the main program, “program.cpp”.
 • When the program is changed, only “program.cpp” needs to be
   compiled again, so the compilation is faster.
   In large software projects this makes a huge difference!

Remark: By convention, C++ program files usually have the suffix:
“.cpp”, “.cc”, “.C”, or “.cxx”.
                                                          [comp151]   27
Class Header File: “.h”


 • Since we don’t want the user who writes “program.cpp” to know
   the details of the class Picture (which can be commercial
   secrets), we need to separate the class interfaces from the class
   implementation.
 • On the other hand, the main program “program.cpp” also needs
   to know about the definition of class Picture and its meth-
   ods before it can be compiled.
 • The solution is to describe the class Picture in 2 files:
   – class header file, “picture.h” — containing the interface
   – class implementation file, “picture.cpp” — containing the im-
     plementation (of constructors and all methods)
                                                                 [comp151]   28
Class Header File: “.h” ..



  /∗ picture.h ∗/
  class Picture
  {
      // ...
      Picture∗ frame(const Picture&);
  }



  /∗ picture.cpp ∗/                      /∗ program.cpp ∗/
  #include ”picture.h”                   #include ”picture.h”

  Picture∗ frame(const Picture& x)       int main()
  {                                      {
       // codes to frame a picture ...       // manipulate pictures...
  }                                      }
                                                      [comp151]   29
Class Header File: “.h” ...




      pix_main*.cpp




      pix_main3.cpp


      pix_main2.cpp     picture.h       picture.cpp


      pix_main1.cpp
                              Picture class
                                                          [comp151]   30
Separate Compilation

In Unix, we may compile the program with the GNU C++ compiler
as follows:

          g++ -c program.cpp
          g++ -c picture.cpp
          g++ -o program program.o picture.o

 • “g++” has many options; “man g++” for details.
 • The first two lines with “-c” option create the object files “pro-
   gram.o” and “picture.o”. They can’t run on their own.
 • The last line creates the executable program called “program”
   (with the “-o” option) by linking the object files together.
 • Linker: is a program that binds together separately compiled
   codes.
                                                     [comp151]   31
Linking Object Files



                  compile

      file1.cpp             file1.o

                                      link
      file2.cpp             file2.o

                                             a.out
      file3.cpp             file3.o




      fileN.cpp             fileN.o
                                                         [comp151]   32
Separate Compilation ..


 • If “program.cpp” is changed but “picture.cpp” is not, then the
   second line is not necessary and you just need:
             g++ -c program.cpp
             g++ -o program program.o picture.o
 • The separate compilation process can be simplified using “gmake”on
   a “Makefile”.
 • If you don’t want the “.o” files, you may compile as follows:
             g++ -o program program.cpp picture.cpp
  But then you don’t get the object files, “program.o” and “pic-
  ture.o”, but only the executable “program”.
                                                            [comp151]   33
Libraries

To produce a working executable, the linker needs to include the
codes for functions that are declared in the standard C++ header
files (iostream.h, string.h, etc.). The corresponding codes can be
found in the standard C++ libraries.

 • A library is a collection of object files.
 • The linker selects object codes from the libraries that contain the
   definitions for functions used in the program files, and includes
   them in the executable.
 • Some libraries are used automatically by the C++ linker, such
   as the standard C++ library. Other libraries have to be specified
   during the linking process with the “-l” option.
   e.g. To link with the standard math library “libm.a”,
              g++ -o myprog myprog.o -lm
                                                        [comp151]   34
Preprocessor Directives: #include

Besides statements allowed in a programming language, some useful
features are added via directives which are handled by a program
called preprocessor before the source code is compiled.

 • In C++, preprocessor directives begin with the # sign in the
   very first column.
 • The #include directive reads in the contents of the named file.
             #include <standard_file.h>
             #include "my_file.h"
 • Angle brackets (< >) are used to include standard header files
   which are searched at the standard library directories.
 • Quotes (" ") are used to include user-defined header files which
   are searched first at the current directory.
 • "g++ -I" may be used to change the search path.
                                                      [comp151]   35
#ifndef, #define, #endif

/* program.h */          /* b.h */             /* c.h */
#include "b.h"           #include "a.h"        #include "a.h"
#include "c.h"           #include "d.h"        #include "e.h"
...                      ...                   ...

 • Since #include directives may be nested, the same header file
   may be included twice!
   – multiple processing ⇒ waste of time
   – re-definition of #define constants/macros
 • Thus, the need of conditional directives
  #ifndef PICTURE_H
  #define PICTURE_H
  // object declarations, class definitions, functions
  #endif // PICTURE_H
                                                         [comp151]   36
What you should take from this lecture


 • Header file
   – separate interface (.h) and implementation (.cpp)
   – re-usability and sharing
 • Separate compilation
   – compiles (to an object code .o)
   – link (object codes and library to produce an executable file)
 • Uses of preprocessor directives
       Comp151



Definition & Declaration
                                                          [comp151]   37
Example: Definition


/∗ progam1.cpp ∗/

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

int global var = 23;                   // global variable definition

void reverse print(const char∗ s)             // function definition
{
    for (int j = strlen(s) - 1; j ≥ 0; --j)
         cout     s[j];
    cout    endl;
}
                                                                 [comp151]   38
Example: Declaration


/∗ progam2.cpp ∗/
#include <iostream.h>

extern int global var;                    // external variable declaration
extern void reverse print(const char∗ s); // external function declaration

void main(int argc, const char∗ argv[])
{
    float local var;                              // local variable definition
    local var = 987.654;

    cout       "global var = "     global var   endl;
    cout       "local var = "    local var    endl;
    cout       "input str (backwards) = ";
    reverse   print(argv[1]);
}
                                                            [comp151]   39
Definition


 • A definition introduces a variable’s or a function’s name and
   type.
 • A variable definition reserves a number of bytes of memory for
   the variable.
 • A function definition generates codes for the function.
 • In both cases, definitions causes memory to be allocated to store
   the variable or function.
 • An object must be defined exactly once in a program.
                                                          [comp151]   40
Declaration


 • The declaration of a variable announces that the variable exists
   and is defined somewhere else (in the same file, or in a different
   file). The connection is made when the object files are linked.
 • A declaration consists of the variable’s name and its type pre-
   ceded by the keyword extern.
 • A declaration does not generate codes, and does not reserve
   memory.
 • There can be many declarations for an object name in a program.
 • If a declaration is used in a file different from that with the
   definition of the object, the linker will insert the real memory
   address of the object instead of the symbolic name.
 • In C++, a variable must be defined or declared to the program
   before it is used.
                                                             [comp151]   41
Advantages of Header Files

In general, a header file provides a centralized location for

 • external object declarations
 • function declarations
 • class definitions
 • inline function definitions

The advantages are:

1. By including the header files, all files of the same piece of software
   are guaranteed to contain the same declaration for a global object
   or function.
2. Should a declaration require updating, only one change to the
   header file needs be made.
                                                         [comp151]   42
Variables



A variable is a symbolic name as-
signed to some memory storage.
 • The size of this storage depends
   on the type of the variable. e.g.        2000
   char is 1-byte long and int is 4-               354               :x
   byte long.                               2004
                                                   76                :y
 • The difference between a variable
   and a literal constant is that a vari-
   able is addressable.
                                                            [comp151]   43
lvalue & rvalue

                      [ interpretation of " x = x + 1 " ]



                 x:                                 x + 1

A variable has dual roles, depending on where it appears in the
program, it can represent

 • lvalue: the location of the memory storage
 • rvalue: the value in the storage

They are so called because a variable represents an lvalue (a rvalue)
if it is written to the left (right) of an assignment statement.
Thus, the following are invalid statements in C++:
  4 = 1;
  grade + 10 = new_grade;
Comp151



Pointers
                                                      [comp151]   44
Pointers: Introduction


                  int x = 361;
                  int* y = &x;            0x1a2b   0x1ffa         :y



 • Related to the concept of “objects”
   (c.f. objects in OOP and “links” in
   HTML documents/webpages).
 • Two main uses:
   1. indirect addressing (as in assem-   0x1ffa                  :x
                                                    361
      bly language programming)
   2. dynamic memory allocation
Use of Pointers: Dynamic Memory Allocation [comp151]                                45




#ifndef IQ1 H                                #include <iostream.h>
#define IQ1 H                                #include ”iq1.h”

#include <iostream.h>                        int main()
                                             {
class IQ                                         IQ∗ x = new IQ("Newton", 200);
{                                                IQ∗ y = new IQ("Einstein", 250);
  private:
    char name[20];                               x→print();
    int score;                                   y→print();

     public:                                     return 0;
       IQ(const char∗ s, int k)              }
       {
           strcpy(name, s);
           score = k;
       }

       void smarter(int k) { score += k; }
                                                              x    Newton
       void print() const                                           200
       {
           cout     "( "    name    " , "
                     score   " )"    endl;
                                                                   Einstein
       }                                                      y
                                                                     250
};

#endif // IQ1 H
                                                                   [comp151]   46
Use of Pointers: Indirect Addressing

    #include <iostream.h>        #include <iostream.h>
    #include ”iq1.h”             #include ”iq1.h”

    int main()                   int main()
    {                            {
        int choice;                  int choice;
        IQ x("Newton", 200);         IQ∗ iq ptr;
        IQ y("Einstein", 250);       IQ x("Newton", 200);
                                     IQ y("Einstein", 250);
        cin     choice;
        if (choice == 1)             cin    choice;
        {                            if (choice == 1)
             x.smarter(50);               iq ptr = &x;
             x.print();              else
        }                                 iq ptr = &y;
        else                                                       Newton
                                                              x:
        {                            iq ptr→smarter(50);            200
             y.smarter(50);          iq ptr→print();
             y.print();
        }                            return 0;
                                 }                                 Einstein
                                                              y:
        return 0;                                                    250
    }
                                                              [comp151]   47
Pointers: Operations

Two basic unary operations:

 • Referencing, &: &x ⇒ address of variable x.
 • Dereferencing/Indirection, ∗: ∗x ⇒ value of the memory loca-
   tion stored in variable x.

Other operations: +, −, ++, −−, new, delete


int x = 1, y = 2, ∗w;
w = &x;                                            // w now points to x
y = ∗w;                                                   // c.f. y = x
∗w = 3;                                                   // c.f. x = 3

IQ∗ x = new IQ("Newton", 200);
x→print();                        // record fields accessed thru pointers
(∗x).print();                 // record fields accessed thru non-pointers
                                                                                         [comp151]   48
Pointers and Records: Linked List Example
#ifndef IQ2 H
#define IQ2 H

#include <iostream.h>

class IQ                                                 Bob
                                     Ada                                   Christy
{                        a           100                 50                 60
  private:
    char name[20];
    int score;
    IQ∗ next;

     public:
       IQ(const char∗ s, int k) { strcpy(name, s); score = k; next = NULL; }

       IQ∗ get next() { return next; }
       void add(IQ∗ p) { next = p; }
       void smarter(int k) { score += k; }
       void print() const { cout    "( "   name      " , "     score   " )"    endl; }

};

#endif                                                                                       // IQ2 H
                                                          [comp151]   49
Pointers and Records: Dynamic Data

Dynamic structures (e.g. linked list, binary tree) that grow/shrink
during execution can be implemented using records and pointers.

 • new : to create a new record
 • delete : to destroy a previously allocated record

e.g. To add Angela between Ada and Bob:

     IQ* p = new IQ(‘‘Angela’’, 70); // allocation of *p
     p->add(a->get_next());          // p->next = a->next
     a->add(p);                      // a->next = p;

e.g. To “fire” Bob:

     IQ* b = a->get_next();                 // b = a->next;
     a->add(b->get_next());                 // a->next = b->next;
     delete b;                              // deallocation of *b
                                                       [comp151]   50
Pointers: Common Bugs! (1)

e.g. To add Angela between Ada and Bob:

     IQ* p = new IQ(‘‘Angela’’, 70); // allocation of *p
     a->add(p);        // a->next = p; BUG! Bob is lost!
     p->add(a->get_next()); // p->next = a->next;



Memory Leak: when there is garbage — allocated storage/structure
which becomes inaccessible.
                                                         [comp151]   51
Pointers: Common Bugs! (2)

e.g. To “fire” Bob:

     IQ* b = a->get_next();              //   b = a->next;
     a->add(b->get_next());              //   a->next = b->next;
     delete b;                           //   deallocation of *b
     cout << b->name;                    //   BUG! What is b?



Dangling Pointer: points to storage that is being used for another
purpose; typically, the storage has been freed.
                                                   [comp151]     52
Pointers and Arrays
                                                     a         a[0]
In C++, the name of an array is also
                                                   a+1         a[1]
treated as a pointer to its first element.          a+2         a[2]

 • a = &a[0].
 • a + j is the same as &a[j].
                                            &a[j] = a+j        a[j]
 • ∗(a + j) is the same as a[j]
 • Thus, any operation that can be
   achieved by array subscripting can          a+(N-1)     a[N-1]

   also be done with pointers.
 • The meaning of (a + j) is:
       new address

     base address (a)
             +
     sizeof(object) ∗j.
                                                       [comp151]   53
Pointers and Arrays: Examples

char∗ strcpy(char∗ destination, const char∗ source)
{
    char∗ d = destination;
    while (∗source != ’\0’)
    {
        ∗destination = ∗source;
        ++destination, ++source;
    }

    ∗destination = ’\0’;
    return d;
}

char∗ strcpy2(char∗ destination, const char∗ source)
{
    char∗ d = destination;
    while (∗source != ’\0’)
        ∗destination++ = ∗source++;

    ∗destination = ’\0’;
    return d;
}
Dynamic Allocation of Multi-Dimensional Arrays[comp151]            54




                                    (T*) a[0]
To dynamically allocate (T**) a                 a[0][0] a[0][1]   a[0][M]

a 2-D (N + 1) × (M + 1)               a[1]
                           a+1                  a[1][0] a[1][1]   a[1][M]
array of IQ during run-
time:

IQ∗∗ a = new (IQ∗) [N+1];
for(int i = 0; i < N+1; i++)
    a[i] = new IQ [M+1];

                                      a[N]
                           a+N                  a[N][0] a[N][1]   a[N][M]
                                                  [comp151]   55
Summary


• Uses of pointer
  – Dynamic memory allocation
  – indirect addressing
• Pointer operations: +, −, ++, −−, new, delete
• Problems of memory leak and dangling pointer
• Dynamic (multi-dimensional) array
    Comp151



Reference Variables
                                                            [comp151]   56
Creating a Reference Variable

A reference is an alternative name (alias) for an object.
int j = 1;
int& r = j;                                        // Now r = j = 1
int x = r;                                             // Now x = 1
r = 2;                                             // Now r = j = 2

 • The notation X& means reference to X.
 • A reference must always be bound to an object. Therefore, it
   must be initialized when it is created:
int j = 1;
int& r1 = j;                                                    // Ok
int& r2;                                                      // Error
                                                              [comp151]   57
Initialization & Assignment

Distinguish between initializing a reference and making an assign-
ment to it:
int j = 10;
int& r = j;
++r;                                         // both r and j become 11
j += 8;                                      // both r and j become 19
r = 7;                                        // both r and j become 7

cout    j     " , "   &j   endl;
cout    r     " , "   &r   endl;

 • The object which a reference refers to cannot be changed after
   initialization. It always refers to the object it was initialized to.
 • Assignment only changes the “value” of its referenced object.
                                                                 [comp151]   58
Call-By-Reference and Reference Arguments

Reference arguments are a special case of references:
int f(int& i) { ++i; return i; }

int main() { int j = 7; cout   f(j)   endl; cout   j   endl; }

Quiz: Rewrite the above program using C pointers so that both
programs produce the same effect.
                                                                    [comp151]   59
Call-By-Reference and Call-By-Value

In C++, an argument to a function may be passed by 2 methods:

 • call-by-reference (CBR)
 • call-by-value (CBV)
int f(int i) { ++i; return i; }

int main() { int j = 7; cout      f(j)   endl; cout   j   endl; }

 • In the call f(j), i is created similarly to the construction:
        CBR        CBV
    int& i = j; int i = j;

 • Note that in CBV, any change to i will not result in any change
   to j.
                                                                     [comp151]   60
Two Reasons for Call-By-Reference

1. When changes in the value of arguments are to be modified by
   the function caller.
2. If you pass a function argument by value, the function gets a local
   copy of the argument. So there is no inadventent modification.
   For large objects, copying is expensive. Passing an object by
   reference does not require copying. But it may modify function
   arguments. How to solve this problem?
class Large Obj
{
   public:
     // Lots of data members
     int height;
};

void print height(const Large Obj& LO){ cout        LO.height(); }

int main() { Large Obj dinosaur(50); print height(dinosaur); }
                                                           [comp151]   61
Pointer vs. Reference

Reference can be thought as a special kind of pointer, but there are
3 big differences to remember!

 • A pointer can point to nothing (NULL), but a reference is always
   bound to an object.
 • A pointer can point to different objects at different times (through
   assignments). A reference is always bound to the same object.
   Assignments to a reference does NOT change the object it refers
   to but only the value of the referenced object.
 • The name of a pointer refers to the pointer object. The * or ->
   operators have to be used to access the object.
   The name of a reference always refers to the object. There are
   no special operators.
                                                                [comp151]   62
Example: Pointer vs. Reference


IQ w("Maxwell", 180);
IQ x("Newton", 200);
IQ∗ a = 0;                                  // Ok: ’a’ bound to nothing

IQ& y = x;                                  // Ok: ’y’ is an alias of ’x’
IQ& z;                                     // Error: uninitialized ref var!

a = new IQ("Einstein", 250);             // Ok: ’a’ points to ”Einstein”
a = new IQ("Galileo", 190);          // Ok: ’a’ now points to ”Galileo”
y = w;                         // ’y’ is STILL an alias of ’x’ NOT ’w’;
                   // the value of ’w’ is copied to ’y’ (’x’)

a→smarter(10); (∗a).print();
y.smarter(20); y.print();
Comp151



const-ness
const                                                       [comp151]   63




 • const: used in C++ to express a user-defined constant — a
   value that can’t be changed.
        const float PI = 3.1416;
 • Constant variables are usually written in capital letters.
 • In the old days, constants are defined by the #define preprocessor
   directive:
        #define PI 3.1416
  Any shortcomings?
 • The const keyword can be regarded as a safety net for program-
   mers. If an object should not change, make it a const object;
   the compiler will issue an error message if you try to change a
   const object.
                                                         [comp151]   64
Example: Constants of Basic Types


#include <stdlib.h>

const int NUM STUDENTS = 117;
const int MAX GRADE = 100;

void assign grade randomly()
{
    srand(time(0));
    int grade[NUM STUDENTS];

    for (int i = 0; i < NUM STUDENTS; ++i)
         grade[i] = (double(rand())/RAND MAX) ∗ (MAX GRADE + 1)
}
                                                                           [comp151]   65
Example: Constant Objects

class Date
{
    int year, month, day;
    Date(int, int, int);                                           // day, month, year
    int difference(const Date&);
    void add month() { month += 1; };
};

int main()
{
    const Date job start(1,4,1998);
    Date x(25,2,2002);

    // How long have I worked in UST in days?
    cout  "Today I have worked "       x.difference(job start)   " days.\n";

    // What about next month?
    job start.add month();                             // Error, but caught by compiler
    cout     "In a month I’ll have worked "       x.difference(job start)  " days.\n";
}
                                                            [comp151]   66
const and Pointers

When using a pointer, two objects are involved: the pointer itself,
and the object pointed to.

 • The syntax for pointers to constants and constant pointers can
   be confusing.
   The rule is that any const to the left of the ∗ in a declaration
   refers to the object pointed to; any const to the right of the ∗
   refers to the pointer itself.
 • It can be helpful to read these declarations from right to left.
char c = ’Y’;
char ∗const cpc = &c;
char const∗ pcc;
const char∗ pcc2;
const char ∗const cpcc = &c;
char const ∗const cpcc2 = &c;
                                                            [comp151]   67
Example: const and Pointers


void example(char∗ p)
{
    char s[] = "COMP171";    // Same as char ∗const s = ”COMP171”
    char p[] = "MATH101";    // Same as char ∗const p = ”MATH101”

    const char∗ pcc = s;                  // Pointer to constant char
    pcc[5] = ’5’;                                           // Error!
    pcc = p;                        // OK, but what does that mean?

    char ∗const cpc = s;                          // Constant pointer
    cpc[5] = ’5’;                                             // OK
    cpc = p;                                                // Error!

    const char ∗const cpcc = s;   // Constant pointer to constant char
    cpcc[5] = ’5’;                                           // Error!
    cpcc = p;                                                // Error!
}
                                                                 [comp151]   68
const and Pointers . . .

Having a pointer-to-const pointing to a non-const object doesn’t
make that object a constant!
int i = 151;
i += 20;                                                              // OK

int∗ pi = &i;
∗pi += 20;                                                            // OK

const int∗ pic = &i;
∗pic += 20;                           // Error! Can’t change i through pic

pic = pi;                                                          // OK
∗pic += 20;                            // Error! Can’t change ∗pi thru pic

pi = pic;
// Warning: assignment to ‘int ∗’ from ‘const int ∗’ discards const
                                                          [comp151]   69
const: References as Function Arguments

While there are 2 good reasons (what are they?) to pass an argu-
ment as a reference, you can (and should!) express your intention to
leave a reference argument of your function unchanged by making
it const. This has 2 advantages:

1. If you accidentally try to modify the argument in your function,
   the compiler will catch the error:
void cbr(Larg Obj& LO)
{
    LO.height += 10;                                         // Fine
}

void cbcr(const Larg Obj& LO)
{
    LO.height += 10;                                        // Error!
}
                                                           [comp151]   70
const: References as Function Arguments . . .


2. You can call a function that has a const reference parameter with
   both const and non-const arguments. Conversely, a function
   that has a non-const reference parameter can only be called
   with non-const arguments.
void cbr(Larg Obj& LO) { cout   LO.height; }
void cbcr(const Larg Obj& LO) { cout    LO.height; }

int main() {
  Large Obj dinosaur(50);
  const Large Obj rocket(100);

    cbr(dinosaur);
    cbcr(dinosaur);
    cbr(rocket);                                             // Error
    cbcr(rocket);
}
                                                         [comp151]   71
const: Member Functions

To indicate that a class member function does not modify the class
object, one can (and should!) place the const keyword after the
argument list.

class Date
{
    int year, month, day;

     public:
       int get day() const { return day; }
       int get month() const { return month; }
       void add year(int y);               // Non-const function
};
                                                             [comp151]   72
Summary

It is good practice to make:
 • objects that you don’t intend to change const.
   const double PI = 3.1415927;
   const Date HandOver(1,7,1997);
 • function arguments that you don’t intend to change const.
   void print height(const Large Obj& LO){ cout   LO.height(): }
 • class member functions that do not change the object const.
   int Date::get day() const { return day; }

				
DOCUMENT INFO
Shared By:
Stats:
views:32
posted:3/12/2010
language:English
pages:78
About