An Overview of C++
Review …
 The C Programming Language
 Array & Pointer
 Function & Memory
 Passing of Parameter
Reference Parameters
 Allow call-by-reference passing of parameters
 Follow formal parameter type with an ampersand (&), and use as if it were
an ordinary parameter.
 Allow the corresponding actual parameter to be changed
Reference Parameter (Continued)
 Without reference parameters
void f (int *p)
{
(*p)++;
}
main( )
{
int i = 2;
f(&i);
}
Reference Parameters (Continued)
 With reference parameters
void f (int& j)
{
j++;
}
main( )
{
int i = 2;
f(i);
}
Reference Variables
int a = 10;
int& ref = a; // a and ref refer to the same data
int b = ref;
// b = 10
a = 15;
// ref also = 15
ref = 20;
// a = 20
Linkage to Other Languages
 The extern construct is used to declare functions defined in other languages
that will be linked to a C++ program.
 The extern construct causes the external version of the function to be
referred to by a normal name instead of the C++ encoded name for the
linker. At the same time, the function can be overloaded just like any other
C++ function, and calls to it are type checked.
 Extern can also specify C++ linkage, so C++ functions can be invoked by
modules written in other languages.
Linkage to Other Languages (Continued)
 For example,
extern “C” void exit(int);
extern “C” {
double sqrt(double);
void printf(char* …);
}
Source Files and Program Organization
C++ programs usually consist of several ASCII files that can compiled
separately and then linked together
 .C files contain the definition of functions. Usually, the main program is
contained in a .C file, separate from the rest of the code.
 .h files contains the declaration of classes and functions. These are called
header files.
The Preprocessor
The following basic preprocessor commands are often used:
#include “filename” include the file; look in the current directory, then the
standard search path.
#include <filemane> include the file; look in the standard search path.
#define name string define a preprocessor variable.
#ifdef name
if name is a defined preprocessor variable, include the
following lines up to #endif
#ifndef name
if name is not a defined preprocessor variable, include the
following lines up to #endif
#endif
mark the end of the range of a #ifdef or #ifndef
Introduction to Classes in C++
Object Oriented Paradigm
 Object
 Class
 Attribute
 Method
 Message
 Encapsulation
 Inheritance
 Polymorphism
 Abstract Data Type: from struct to class
Classes in C++
class Myclass
// class head
{
// indicates beginning of class body
public:
// public data and functions
type myfunc( );
protected:
// protected data and functions
private:
// private data and functions
type myvar;
};
// indicates end of class body
Levels of Data Access
Information hiding is a formal mechanism for restricting user access to the
internal representation of a class type
Members are declared as
 public
 protected
 private
Member Functions
 Any function that is declared as part of a class is called a member function
 Member functions are invoked by sending messages to an instance of the
class
 The . (dot) operator is the “message send” operator:
instance.function(parameters)
 Member functions within the same class can call each other without using
the . (dot) operator
Rational Number Class
class Rational
// implement rational numbers with addition
{
// the only operation defined
public:
void initialize(int num, int den);
void print ( );
Rational add(Rational r);
private:
int numerator;
int denominator;
int gcd(int i, int j);
void commonDenominator(Rational& r);
};
Review of .h and .C
 Class declarations typically are placed in a dot h (.h file).
 Member function definitions typically are placed in a .C file.
 The .C file requires an “include” statement:
#include “Class_name.h”
Scope Resolution Operator

:: is used to define the code for a member function outside of its class declaration.

It can also be used to reference global variables even when the same name has been
used for a local.
For example,
int a = 15;
int f( )
{
int a = 100;
cout << ::a;
}
will print the value 15.
Rational Number Class
#include “Rational.h”
void Rational::initialize(int numerator, int denominator)
{
// initialize the numerator and denominator members
this->numerator = numerator;
this->denominator = denominator;
}
Rational Number Class (Continued)
#include “Rational.h”
#include <math.h>
int Rational::gcd(int i, int j)
{
// Find greatest common divisor of 2 integers
int divisor;
i = abs(i);
j = abs(j);
for (divisor = (i<j) ? i : j;
divisor > 1 && (i % divisor != 0 || j % divisor != 0);
divisor--);
return divisor;
}
Rational Number Class (Continued)
void Rational::commonDenominator(Rational& r)
{
// given two rational numbers, convert them
// to have a common denominator
int multiplier1, multiplier2;
int divisor = gcd(denominator, r.denominator);
multiplier1 = denominator / divisor;
multiplier2 = r.denominator/divisor;
numerator *= multiplier2;
denominator *= multiplier2;
r.numerator *= multiplier1;
r.denominator *= multiplier1;
}
Rational Number Class (Continued)
Rational Rational::add(Rational r)
{
Rational temp = *this;
Rational i;
temp.commonDenominator(r);
i.initialize(temp.numerator + r.numerator, temp.denominator);
return i;
}
void Rational::print( )
{
cout << numerator << “/” << denomiator;
}
Using the Rational Number Class
Rational a, b, c;
a.initialize(1, 2);
b.initialize(2, 3);
c.initialize(1, 1);
a.print( );
b.print( );
c = a.add(b);
// Can’t do:
//
print();
a.print( );
//
a.commonDenominator(b);
b.print( );
//
cout << a.denominator;
c.print( );
Notes About Class Definitions
 Classes and structs are equivalent, except that all members are private by
default in a class, and public by default in a struct.
 The keyword, this, references a pointer to the receiver of a message.
 Data items in the receiver can be referenced directly by using the instance
variable name.
 Member functions can access the private data of an instance of the class.
In other words, only member functions can “reference and dereference”
private class instance variables.
Some Common Errors
 Leaving off the semicolon after the class declaration gives the following
errors (among others):
bad base type: class int
class Rational defined as return type for gcd()
(did you forget a ‘:’ after ‘}’ ?)
class Rational undefined
 Leaving off the Rational::, in front of the definition of gcd gives the
following error at link time:
Undefined entry, name:
(Error 28) “gcd__8RationalFiT1”
Constructors and Destructors
Rational Number Class
class Rational
// implement rational numbers with addition
{
// the only operation defined
public:
void initialize(int num, int den);
void print ( );
Rational add(Rational r);
private:
int numerator;
int denominator;
int gcd(int i, int j);
void commonDenominator(Rational& r);
};
Constructor Syntax
Class Myclass
{
Public:
Myclass( );
// void constructor
Myclass(int n);
// one-parameter constructor
…
};
#include “Myclass.h”
Void main( )
{
}
Myclass i;
// invokes void constructor
Myclass j(3);
// invokes the one-parameter constructor
Constructor
 A member function with the same name as the class is called a constructor.
 Constructors are called whenever a member of the class is created
(declarations, parameter passing, function returns).
 Constructor declarations can appear only inside of class declarations.
 Any number of constructors are allowed.
 Constructors cannot have return types.
Rational Number Class with Constructors-1
class Rational
// implement rational numbers with addition
{
// the only operation defined
public:
Rational( );
// void constructor
Rational(int n);
// one-parameter constructor
Rational(int n, int d); // two-parameter constructor
void print ( );
Rational add(Rational r);
private:
int numerator;
int denominator;
int gcd(int i, int j);
void commonDenominator(Rational& r);
};
Rational Number Class with Constructors-2
class Rational
// implement rational numbers with addition
{
// the only operation defined
public:
Rational(){
numerator = 0;
denominator = 1;
}
Rational(int n){
numerator = n;
denominator = 1;
}
Rational(int n, int d){
numrator = n;
denominator = d;
}
…
Rational Number Class with Constructors-3
The original add function
Rational Rational::add(Rational r)
{
Rational temp = *this;
Rational i;
temp.commonDenominator(r);
i.initialize(temp.numerator + r.numerator, temp.denominator);
return i;
}
The new add function using constructors
Rational Rational::add(Rational r)
{
Rational temp = *this;
temp.commonDenominator(r);
return Rational(temp.numerator + r.numerator, temp.denominator);
}
Default Constructor Arguments
With default arguments and a single constructor, it is possible to declare:
Rational a, b(3), c(1,4)
calss Rational
{
Rational (int num=0, int den=1)
{
if(den < 0){
num = -num;
den = -den;
}
numerator = num;
denominator = den;
}
…
};
Inline Code
 Inline causes the actual code for a function to be substituted for a call to the
function.
 Member functions can be made inline by putting their definition (that is,
their code) within the class declaration or by preceding their definition,
outside of the class, by the keyword inline.
 Any other function is made inline by preceding its definition with the
keyword inline.
 Inline is a suggestion to the translator. For example, functions containing
loops will not be made inline.
Inline Code (Continued)
calss Rational
// With in-line constructor
{
Rational (int num=0, int den=1)
{
if(den < 0){
num = -num;
den = -den;
}
numerator = num;
denominator = den;
}
…
};
Inline Code (Continued)
An alternative
inline Rational::Rational (int num=0, int den=1)
{
if(den < 0){
num = -num;
den = -den;
}
numerator = num;
denominator = den;
}
Vectors of Class Instances
 A class must have a constructor with no arguments (a void constructor), in
order to declare a vector of instances of it, without explicitly initializing the
entire vector.
 A constructor with all of its arguments having default values is equivalent
to a void constructor.
 Arrays of class instances can be initialized using any combination of
constructors. There must be enough initializers for the entire vector.
Vectors of Class Instances (Continued)
main()
{
Rational fractions1[25];
Rational fractions2[3]={Rational(1,2), Rational( ), 4};
fractions1[0] = Rational(1,4);
fractions2[1] = Rational(1,2);
fractions2[1].print( );
}
Destructor
 A destructor is a function named by ~className.
 A destructor is invoked whenever an element of the class is destroyed
(leaving scope, dynamic freeing, deallocation of temporary)
 Destructor declarations can appear only inside of class declarations.
 There can be, at most, one destructor.
 Destructors cannot have parameters or return types.
Destructor (Continued)
class Rational
// With Destructor
{
public:
…
~Rational( )
{
cout << “Instance of Rational destroyed” << endl;
}
};
Some Common Errors
If you have provided one or more constructors, but not a void constructor,
the following errors are possible:
 The declaration Rational r[25]; causes the following error message:
array of class Rational that does not have a
constructor taking no arguments
 The declaration Rational r; gives the following error message:
argument 1 of type int expected for Rational::Rational( )
Static Members
 Members declared to be static are shared among all instances of a class
 If a static member is public, it can be referred to outside of the class:
className::staticMember;
 Static members cannot be initialized when declared. Therefore, if they are
instances of a class, the class must have a void constructor, if it has any
constructors.
 A static member, whether private or public, must be initialized, exactly
once, at file scope:
type className::staticMember = initialValue;
Static Members (Continued)
class Rational
{
public:
…
int howMany( );
private:
…
static int numRationals;
};
Static Members (Continued)
In each constructor, add the following statement:
numRationals++;
In the destructor, add the follwing statement:
numRational--;
Initialize the static somewhere at file scope:
int Rational::numRationals = 0;
Implement the howMany( ) function:
int Rational::howMany( )
{
return numRationals;
}
Static Member Functions
 Member functions accessing only static members can be declared static.
Static member functions can be called though a member or by
ClassName::ftn( ).
For example,
Rational::howMany( )
 Static member functions have no this pointer. Any explicit reference to this,
or to a nonstatic member, causes a compile-time error.
Static Member Functions
class Rational
{
public:
…
static int howMany( );
private:
…
static int numRationals;
};
// Return the number of Rationals at any time
Overloading Functions
Overloading Functions
The following are allowed in the same program:
int f(int a);
float f(float a);
int f(int a, int b);
int f(int a, float b);
int f(char a);
int f(int a, int b, int c, …)
Overloading Functions (Continued)
 Given the declarations on the previous slide, the function declaration
float f(int a)
generates the error message
two different return value types for f( ): int and float
 Given the declarations on the previous slide, the function declaration
int f(int a, int b, int c=1);
generates the error message
two exact matches for f( ): int (int, int, int) and int (int, int)
Overloading Functions (Continued)
 Overloaded functions must be distinguishable by the number and type of
arguments.
 Return type cannot be used to distinguish overloaded functions.
 The number, type, and order of the arguments establishes the function
signature
Default Arguments
 When default arguments are used, the resulting function is equivalent to a
set of functions whose members are that function with each possible
number of arguments.
For example, the function declaration
void f (int a = 1, int b = 2, int c = 3);
is equivalent to the four declarations
void f( );
void f(int);
void f(int, int);
void f(int, int, int);
Argument Matching
 Each argument in a call to an overloaded function is compared to the
corresponding arguments in the declaration.
 The compiler will choose the function for which each argument resolution
is the same or better than for the other functions.
 If there is either no match or an ambiguous match, a compilation error is
generated.
 The argument matching algorithm distinguishes between constant and
nonconstant pointer and reference arguments.
Argument Matching (Continued)
The comparison takes place using following steps:
1. Look for an exact match
2. Look for a match using promotions
3. Look for a match based on standard conversions
(for example, SomeClass* to void*)
4. Look for a match using user-defined conversions. Only one level of userdefined conversion will be used
Argument Matching
Given the declarations
void f (int, float);
void f(float, int);
the call
f(1.5, 1.5);
Gives the error message
two standard conversions possible for f():
void (int, float) and void (float, int)
Constant Member Functions
 A member function can be declared as constant by adding the keyword
const between the argument list and the body of the function.
 Only constant member functions can be sent to class instances declared as
constant.
 It is illegal to declare a member function as constant if it modifies an
instance variable.
 There can be constant and nonconstant version of a member function. The
function is selected, based on whether or not the receiver is a constant.
Constant Member Functions
class Rational
{
…
void print( ) const;
};
void Rational::print( ) const
{
…
}
main()
{
const Rational r(3,5);
r.print();
}
Overloading Operators
Rational Number Class
Rational Rational::add(Rational r)
{
Rational temp = *this;
temp.commonDenominator(r);
return Rational(temp.numerator + r.numerator, temp.denominator);
}
Overloading an Operator
Operator overloading is redefining and operator that has a built-in function.
 The function name consists of the keyword operator, followed by the
operator symbol
For example, given a String class, we can write the following function to
concatenate two Strings:
String operator+ (String x);
The we can concatenate the Strings:
String a, b, c;
a = b + c;
Overloading Operators
class Rational
{
public:
…
Rational operator+ (Rational);
protected:
private:
int numerator;
int denominator;
int gcd(int i, int j);
void commonDenominator(Rational& r);
};
Overloading Operators (Continued)
Rational Rational::operator + (Rational r)
{
Rational temp = *this;
temp.commonDenominator(r);
return Rational(temp.numerator+r.numerator, temp.denominator);
}
Using + operator:
Rational a(1,4), b(1,3), c(1,1);
c = a + b;
// c = a.operator+(b);
Overloading Operators (Continued)
 Functions can be named with standard C++ operators.
 The types of the operands are used to distinguish between the various
declarations
 The operator does not imply any particular semantics.
 Precedence follows standard C++ precedence rules.
 It is possible to overload the prefix and postfix increment (++) and
decrement (--) operators.
Overloading Operators (Continued)
 op1 binaryOp op2 is interpreted as op1 receiving the message binaryOp
with the argument op2.
 The expression can also be written as follows:
op1. oprator binaryOp(op2)
For example
r1 + r2 or r1.operator+(r2)
Friends
 Classes or functions can be declared to be a friend of a class.
 Friends have access to the private members of a class.
 Friend functions are not received by class instances and thus do not have
access to this pointer.
 Friend functions are necessary when the left operand is not an instance of
the class being defined.
Friends versus Members
class Rational
{
public:
friend Rational operator+(Rational, Rational);
}
Versus the member function
class Rational
{
public:
Rational operator+(Rational);
};
Friends versus Members (Continued)
 Binary operators that are friend functions have two arguments; those that
are member functions have one. Unary operators that are friend functions
have one argument; those that are member functions have none.
 Constructors, destructors, and virtual functions must be members.
 The overloaded operators = (assignment), ( ) (function call), [ ]
(subscripting), and -> (class member access) must be member functions,
not friends.
 Operations modifying state should be members.
 Choose members when possible.
A Special Friend
class Rational
{
friend ostream& operator << (ostream&, Rational&);
…
};
ostream& operator << (ostream& s, Rational& r)
{
return (s << r.numerator << “/” << r.denominator << “\n”);
}
Constructors for Type Conversion
class Rational
{
public:
Rational operator+(Rational);
Rational operator+(int);
friend Rational operator+(int, Rational);
};
Constructors for Type Conversion (Continued)
Using implicit type conversion is easier:
class Rational
{
public:
Rational (int, int=1);
// or any constructor that takes one int
friend Rational operator+(Rational, Rational);
…
};
Constructors for Type Conversion (Continued)
 Both of these allow:
Rational a(1, 2), b(1, 1);
b = a + a;
b = a + 1;
b = 1 + a;
 Using implicit conversion allows the addtion function to be written once
instead of three times.
Constructors for Type Conversion (Continued)
 A constructor with one argument is a user-defined conversion operator that
can be implicitly applied
 Only one level of conversion will be implicitly applied.
 Conversion can be explicitly requested by casting:
typeName(expression)
 This notation can also be used for basic types as an alternative to the
traditional C cast notation.
 Member functions are invoked only for real objects; friend functions can be
called for an object created by implicit conversion.
Conversion Operators
class Rational
{
…
public:
operatior int( )
//convert from Rational to int
{
return int (float (numerator) / denominator + 0.5);
}
…
}
Constructors for Type Conversion
 There are several limitations in using constructors for type conversion:
 They may not allow implicit conversion from a user-defined type to a
basic type
 They must modify the declaration for an old type when specifying a
conversion from a new type to it.
 When both forms of type conversion are in a program, the compiler flags
ambiguities. For example, if both the one-parameter constructor for
Rational and the int( ) operator exist, given
Rational a(1, 2);
a + 1 generates a compile-time error, because a can be converted to an int,
or 1 can be converted to a Rational.
Inheritance – Derived Classes
Employee Inheritance Hierarchy
Employee
base class
SalariedEmp
HourlyEmp
derived classes
Derived Classes
 Derived classes are used to create a class hierarchy.
 The superclass is called the base class.
 The subclass is called the derived class.
 Friendship is not inherited.
Specifying Inheritance
In the class declaration, we follow
class name
with
:superclass
or
:private superclass
or
:public superclass
Employee Inheritance Example
class Employee
{
public:
Employee( );
Employee(int emp_id, char *emp_name);
Employee(const Employee &e);
~Employee( );
float calculate_pay( );
void set_tax_rate(float new_rate);
void print( );
protected:
float gross_pay;
private:
int id;
char *name;
float tax_rate;
};
Employee Inheritance Example (Continued)
class HourlyEmp : public Employee
{
public:
HourlyEmp( );
HourlyEmp(int emp_id, char *emp_name);
HourlyEmp(int emp_id, char *emp_name, float rate);
HourlyEmp(const HourlyEmp &h);
~HourlyEmp( );
float calculate_pay( );
void set_hours(float worked);
void set_pay_rate(float rate);
void print( );
private:
float hours_worked;
float pay_rate;
};
Member Visibility
Class members are divided into three categories of accessibility:
private member
Can be accessed only by the member functions and
friends of its class
protected member
Behaves as a public member to a derived class; it
behaves as a private member to the rest of the
program.
public member
Is accessible from anywhere within a program.
Inheritance and Visibility
Private inheritance changes the visibility of the base class members inherited
by the derived class:
private member
remains private in the derived class and is not
accessible by the derived class methods
protected member
becomes private in the derived class
public member
becomes private in the derived class
When public inheritance is used, the visibility of the base class members is not
changed in the derived class
Storage Layout for Class Instances
base class
data
derived class
data
Visibility between Objects of the Same Class
What can an object access within ITSELF and other objects of the SAME
CLASS? [What part of Y can Z access?]
Public inheritance
A
B
B Y, Z;
Private inheritance
Base class parts
(A part of Y)
public
protected
private
Y
Y
n
Y
Y
n
Derived class parts
(B part of Y)
public
protected
private
Y
Y
Y
Y
Y
Y
Visibility between Base and Derived Class Object
What parts of an object can be accessed by another object of a DERIVED
class? [What part of Y can be accessed by Z?]
Public inheritance
A
B
B Z;
A Y;
Base class parts
(A part of Y)
public
protected
private
There is no B part of Y !
Y
Y
n
Private inheritance
Y
n
n
External Visibility
What parts of an object can be accessed from OUTSIDE its inheritance
hierarchy? [What part of Z can be accessed from main?]
Public inheritance
A
B
B Z;
Private inheritance
Base class parts
(A part of Y)
public
protected
private
Y
n
n
n
n
n
Derived class parts
(B part of Y)
public
protected
private
Y
n
n
Y
n
n
Visibility of Members Example
class A
{
public:
int a1;
void fa( ) { a1 = a2 = a3 = 0; }
protected:
int a2;
private:
int a3;
};
main( )
{
A x;
x.a1 = 1;
x.a2 = 1;
main( ) cannot access A::a2: protected member
x.a3 = 1;
main( ) cannot access A::a3: private member
}
Visibility of Members Example (Continued)
class B : public A
{
public:
int b1;
void fb( );
protected:
int b2;
private:
int b3;
};
void B::fb( )
{
b1 = b2 = b3 = 0;
a1 = 1;
a2 = 2;
a3 = 3;
B::fb() cannot access A::a3: private member
}
Visibility of Members Example (Continued)
main( )
{
B y;
y.a1 = 2;
y.fa( );
y.a2 = 2;
main( ) cannot access A::a2: protected member
y.a3 = 2;
main( ) cannot access A::a3: private member
y.b1 = 2;
y.b2 = 2;
main( ) cannot access B::b2: protected member
y.b3 = 2;
main( ) cannot access B::b3: private member
}
Visibility of Member Example (Continued)
class C : private A
{
public:
int c1;
void fc( );
protected:
int c2;
private:
int c3;
};
void C::fc( )
{
c1 = c2 = c3 = 0;
a1 = 1;
a2 = 2;
a3 = 3;
C::fc() cannot access A::a3: private member
}
Visibility of Members Example (Continued)
The following statements cause the indicated compiler errors:
main( )
{
C z;
z.a1 = 3;
//z.fa(); would be similar
main( ) cannot access a1: A is a private base class
z.a2 = 3;
main() cannot access A::a2: protected member
z.a3 = 3;
main() cannot access A::a3: private member
z.c1 = 3;
z.c2 = 3;
main() cannot access C::c2: protected member
z.c3 = 3;
main() cannot access C::c3: private member
}
Summary of Access Rules for C++
 C++ provides function and data protection through a combination of the
following:
 public, private, and protected class members
 inheritance
 friendship
Invoking Parent Class Constructors
 In the constructor for a derived class, its parent’s constructor may be passed
data by putting
: BaseClassName (arguments)
after the function header. For example,
SalariedEmp (int id, char *name) : Employee(id, name) { }
This allows the base class part of the object to be initialized at object
construction.
 The parent’s constructor is always invoked before the body of the derived
class constructor
Employee Constructor Examples
Employee::Employee( ) : id(0), tax_rate(0)
{
name = strdup(“”);
gross_pay = 0;
}
Employee::Employee (int emp_id, char *emp_name)
{
id = emp_id;
name = strdup(emp_name);
gross_pay = tax_rate = 0;
}
Employee::Employee (const Employee& e)
{
id = e.id;
name = strdup(e.name);
gross_pay = e.gross_pay;
tax_rate = e.tax_rate;
}
Employee Constructor Examples (Continued)
HourlyEmp::HourlyEmp( )
{
hours_worked = pay_rate = 0;
}
HourlyEmp::HourlyEmp(int emp_id, char *emp_name) : Employee(emp_id, emp_name)
{
hours_worked = pay_rate = 0;
}
HourlyEmp::HourlyEmp(int emp_id, char *emp_name, float rate) :
Employee(emp_id, emp_name), pay_rate(rate), hours_worked(0)
{ }
HourlyEmp::HourlyEmp(const HourlyEmp& h) : Employee(h)
{
hours_worked = h.hours_worked;
pay_rate = h.pay_rate;
}
Inherited Functions
 Member functions inherited from a public base class can be sent to
instances of a derived class.
 An instance of a derived class can be passed as a parameter declared to be
an instance of a public base class from which it is derived.
 A reference to a derived class can be passed as a parameter declared to be a
reference to an instance of a public base class from which it is derived.
 A pointer to a derived class can be passed as a parameter declared to point
to an instance of a public base class from which it is derived.
Inherited Functions (Continued)
#include <string.h>
void test_function(Employee);
main( )
{
Employee e1(101, “Chris”), e2;
HourlyEmp h1(102, “Kerry”), h2(103, “Lee”, 25.00);
h2.set_hours(41.0);
h2.set_tax_rate(0.18); // method inherited from Employee
cout << “Pay = “ << h2.calculate_pay() << endl;
test_function(e1);
test_function(e2);
}
void test_function(Employee x)
{
x.print( );
cout << endl;
}
Pointers to Class Instances
 A pointer to a base type is allowed to point to an instance of a class derived
from it. This is not true if private inheritance was specified between the
base and derived classes.
 Reference to a base class may also be assigned an instance of a class
derived from it
 To allow a pointer to a derived class to point to an instance of its superclass,
it must be explicitly converted with an appropriate constructor or type
conversion operator.
Pointers to Class Instances (Continued)
main( )
{
Employee e1(101, “Chris”), e2;
HourlyEmp h1(102, “Kerry”), h2(103, “Lee”, 25.00);
Employee *eptr;
HourlyEmp *hptr;
eptr = &e1;
hptr = &h2;
eptr = &h1;
// base class ptr points to derived class object
// hptr = &e2;
is not allowed
// hptr = eptr;
is not allowed
eptr->print( );
// use the pointer to invoke Employee::print
hptr->print( );
// invoke HourlyEmp::print
hptr = (HourlyEmp *) eptr;
}
// ok, but Dangerous!
Classes That Allocate Storage
Storage Allocation - New
This statement allocates storage for one object of type int.
int *ptr = new int;
This statement allocates storage for an array of ten objects of type int.
int *ptr = new int[10];
This statement allocates storage for one object of type Myclass. After storage
is allocated, the value 1024 is passed to the constructor and the storage is
initialized.
Myclass *ptr = new Myclass(1024);
Storage Allocation – New (Continued)
 new is a unary operator that takes a type as its operand and returns a pointer
to free storage sufficient to hold an instance of that type.
 Vectors of objects may be allocated by using an array specifier in the
operand of new.
 When new fails, it calls the function pointed to by the pointer
_new_handler. If no such pointer is found, it returns 0. The pointer can be
explicitly set, or the function set_new_hander can be called.
 new can be overloaded.
set_new_handler
#include <new.h>
void noSpace( )
{
cerr << “New Failed” << endl;
exit(1);
}
main( )
{
set_new_handler(noSpace);
…
}
Polygon Class Description
Polygons are geometric figures with one or more sides. They have the
following methods:
 A constructor that takes the number of sides and allocates storage for them.
 A void constructor that sets the number of sides to 0.
 A method to assign the length of the side of a polygon.
 A method to compute the perimeter of a polygon.
 A method to print the polygon.
 A method to compute the area of a polygon.
Polygon Class
class Polygon
// implements geometric shapes of 1 or more sides.
{
// uses ints to represent the lengths of the sides.
public:
Polygon( );
Polygon(int n_sides);
void assignSide(int which_side, int len);
int perimeter( );
void print( );
int area( );
protected:
int *sides;
private:
int num_sides;
};
Polygon Class (Continued)
Polygon::Polygon(int n_sides)
{
num_sides = n_sides;
sides = new int [num_sides];
for(int i = 0; i < num_sides; i++)
assignSide(i,0);
}
Polygon::Polygon()
{
num_sides = 0;
sides = NULL;
}
Polygon Class (Continued)
void Polygon::assignSide(int which_side, int len)
{
if(which_side < num_sides)
sides[which_side] = len;
else
cerr << “assignSide: value out of range” << endl;
}
int Polygon::perimeter( )
{
int sum = 0;
for (int i = 0; i < num_sides; i++)
sum += sides[i];
return sum;
}
Polygon Class (Continued)
int Polygon::area( )
{
cerr << “Area undefined for generic polygon” << endl;
return 0;
}
void Polygon::print( )
{
cout << “A polygon with sides : “ << endl << “\t”;
for(int i = 0; i < num_sides; i++)
cout << “ “ << sides [i];
}
Using the Polygon Class
Polygon triangle(3);
main()
{
int side;
for (int i = 0; i < 3; i++)
{
cin >> side;
triangle.assignSide(i, side);
}
cout << triangle.perimeter( );
}
Storage Allocation - Delete
 delete is a unary operator that is applied to a pointer returned by new. It
explicitly deallocates the storage pointed to by the pointer.
 For arrays of user-defined objects, use the following form:
delete [ ] pointer;
This ensures that the destructor is called for each element of the array.
The compiler cannot distinguish a pointer to a vector from a pointer to a
single object.
 delete can be overloaded
Polygon Class Destructor
Polygon::~Polygon( )
{
delete sides;
}
Memberwise Assignment Polygons
Polygon pentagon(5), triangle(3);
Polygon aShape;
aShape = triangle;
pentagon
triangle
aShape
5
5
5
Overloading =
Polygon& Polygon::operator = (Polygon& p)
{
if(this != &p) {
int *new_sides = new int[p.num_sides];
for(int i = 0; i < p.num_sides; i++)
new_sides[i] = p.sides[i];
delete sides;
sides = new_sides;
num_sides = p.num_sides;
}
return (*this);
}
Assignment versus Initialization
 Assignment and initialization are not the same.
 A user-defined assignment operator is not applied to an uninitialized object.
 Initialization (the copy constructor) is used when class instances are
initialized in declarations, for passing instances as function arguments, and
for returning instances from functions.
The Copy Constructor
Polygon::Polygon(const Polygon& p)
{
num_sides = p.num_sides;
sides = new int [num_sides];
for (int i = 0; i < num_sides; i++)
sides[i] = p.sides[i];
}
Example of Constructor Invocation
Polygon test(Polygon p)
// passing a to test: copy constructor
{
return p;
// return Polygon from test: copy constructor
}
main()
{
Polygon a(5);
// 1-parameter constructor
Polygon b = Polygon(3);
// 1-parameter constructor (Polygon b(3))
Polygon c = a;
// copy constructor
Polygon d;
// void constructor
d = test(a);
// assign result of test to d: assignment operator
// destruct function argument: destructor
// destruct temporary function result: destructor
}
// destruct d, c, b, a : destructor
Classes Allocating Storage
 When a class dynamically allocates storage, each of the following is
necessary in the class:
 regular constructor(s)
 destructor
 overloaded assignment operator
 copy constructor
Default Memberwise Copy
 If class does not provide an overloaded assignment operator or copy
constructor, when assignment or copying of instances is done, each base
class and member class object in it has
 its assignment operator or copy constructor invoked, if it exists
 memberwise copy applied otherwise
Default Memberwise Copy (Continued)
 If a class does provide an overloaded assignment operator or copy
constructor, it is invoked when assignment or copying of instances is done.
It is the responsibility of the class operators to invoke the base class or
member class operators, or both, as necessary.
 If both a derived class and a base class define assignment operators and a
derived class object is assigned to a base class object, the type of the lefthand operand determines the assignment operator used.
Virtual Functions
Polygon Class
class Polygon
// implements geometric shapes of 1 or more sides.
{
// uses ints to represent the lengths of the sides.
public:
Polygon( );
Polygon(int n_sides);
void assignSide(int which_side, int len);
int perimeter( );
void print( );
int area( );
protected:
int *sides;
private:
int num_sides;
};
A Polygon Hierarchy
Polygon
Triangle
Rectangle
Square
Using the Polygon Classes
Polygon p1(5);
Triangle t1, t2(10, 10, 10);
Rectangle r1, r2(10, 20);
Square s1, s2(10);
p1.assignSide(0, 99);
cout << t2.perimeter() << endl;
t2.print(); cout << endl;
cout << r2.area() << endl;
r2.print(); cout << endl;
cout << s2.area() << endl;
s2.print(); cout << endl;
Accessing Polygons through Pointers
Polygon *p[50];
Triangle t1, t2(10, 10, 10);
Rectangle r1, r2(10, 20);
Square s1, s2(10);
p[0] = &t1;
p[1] = &r2;
p[2] = &s2;
…
cout << p[i]->area() << endl;
p[i]->print();
Accessing Polygons through Pointers (Continued)
The code for print() and area()
is found in this class
Polygon
Triangle
Rectangle
Square
Virtual Functions
If we change the declaration of the function area in Polygon to
virtual int area( );
And the declaration of function print in Polygon, to
virtual void print( );
Then print and area are dynamically bound to the code, appropriate to the
object to which they are sent.
Virtual Function (Continued)
Polygon
The code for p[1]->print( ), and
p[1]->area( ), is found in this class
Triangle
The code for p[0]->print( ), and
p[0]->area( ), is found in this class
Rectangle
The code for p[2]->print( ), and
p[2]->area( ), is found in this class
Square
Virtual Function (Continued)
 The keyword virtual is specified once for the inheritance hierarchy by
placing it in the root of the tree or subtree. It is used to dynamically bind a
member function to the appropriate code, based on the type of the receiver.
 The derived classes can redefine the virtual function or inherit it. They can
also define additional virtual functions.
 The access level (public, private, or protected) is specified by the type
through which it is invoked.
Pure Virtual Functions
 In a base class, the virtual function declaration can be specified as follows:
virtual retType name(arguments) = 0;
 This function is called a pure virtual function. The class declaring it is
called an abstract class.
 It is illegal to create instances of classes containing one or more pure
virtual function declarations.
 A pure virtual function that is not redefined in a derived class will be
inherited as a pure virtual function, and the derived class will become an
abstract class.
Virtual Destructors
 Given pointers to a base class (which may point to instances of the derived
classes), if we delete them, we invoke the destructor for the base class. To
overcome this, we use virtual destructors.
 To declare a destructor as virtual, precede its declaration with the keyword
virtual, in the base class.
 Even though destructors in a derived class don’t have the same name as in
the base class, they can still be declared virtual.
Descargar

슬라이드 1 - Chonbuk