0% found this document useful (0 votes)
10 views

5 Object Programming Essentials

Uploaded by

Youness MOUZAKI
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views

5 Object Programming Essentials

Uploaded by

Youness MOUZAKI
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 85

5 Object programming

essentials
OBJECIFS
• 5.1 Basic concepts of object programming
• 5.2 A stack: a view from two different perspectives
• 5.3 Anatomy of the class
• 5.4 Static components
• 5.5 Objects vs. pointers and objects inside the objects
5.1 Basic concepts of object programming

De la programmation classique à la POO


5.1.1 Classes and objects in real life (1)
• In the procedural approach, we can distinguish two different and
separate worlds: the world of data and the world of code.
• The world of data is populated by variables of different types, while
the world of code is inhabited by code grouped into functions.
• Functions are able to use data but not vice versa.
• The object approach suggests a completely different way of thinking.
The data and the code are enclosed together in the same world,
divided into classes.
5.1.3 Class – what is it? (1)
The specialized classes are called “sub-classes”.
The “vehicles” class will be a “super-class” for them all.
5.1.4 Class – what is it? (2)

Each subclass is more specialized (or more specific)


than its superclass. It also means that each superclass
is more general (more abstract) than all its subclasses.
5.1.5 Object – what is it?
• A class is a set of objects. An object is a being belonging to a class. An
object is an incarnation of requirements, traits and qualities assigned
to a specific class.
5.1.6 Inheritance
We’re now ready to define one of the fundamental concepts of object
programming, called “inheritance”. Any object bound to a specific level of a class
hierarchy inherits all the traits (as well as requirements and qualities) defined
inside any of the superclasses.
5.1.7 What does any object have?
• The object programming convention assumes that every existing
object may be equipped with three groups of attributes:
• an object has a name that uniquely identifies it within its home namespace
(although there may be some anonymous objects, too)
• an object has a set of individual properties that make it original, unique or
outstanding (although there is the possibility that some objects may have no
properties at all)
• an object has a set of abilities to perform specific activities that can change
the object itself or some of the other objects
5.1.7 What does any object have?
Here are two sample phrases that are good examples:
“Max is a large cat who sleeps all day”
Object name = Max
Home class = Cat
Property = Size (large)
Activity = Sleep (all day)
“A pink Cadillac went quickly”
Object name = Cadillac
Home class = Wheeled vehicles
Property = Colour (pink)
Activity = Drive (quickly)
5.1.8 Why all this?
• Class is a model of a very specific part of reality reflecting properties
and activities found in the real world.
• The classes defined at the beginning are too general and imprecise to
cover the largest possible number of real cases.
• The new class may add new properties and new activities and
therefore may be more useful in specific applications.
• The class itself isn’t able to create an object – you have to create it
yourself. But the “C++” language allows you to do this.
• We’ve defined a class. The class is rather poor: it has neither
properties nor activities. class OurClass{ } ;
5.1.9 The very first object
The newly defined class becomes an equivalent of a
type, and we can use it as a type name.

class OurClass{ } ;
OurClass ourobject;

Let's leave the classes alone for a moment.


5.2 A stack: a view from two different perspectives
5.2.1 Stack aka LIFO (1)
• A stack is a structure developed to store
data in a very specific way.
• The alternative name for a stack is LIFO: “Last
In – First Out”. The coin that goes onto the
stack last comes off first.
• A stack is an object to two elementary operations conventionally
named “push” (when a new element is placed on the top) and “pop”
(when an existing element is taken away from the top).
• Let’s try to implement a stack in “C++”. It’ll be able to store int values
only. We’ll show you how to do it in two independent approaches:
procedural and objective.
The procedural approach
5.2.3 Stack pointer
• int stack [100] ;
• The array isn’t enough to implement a stack. We need a variable that
can be responsible for storing a number of elements currently
stored on the stack called a “stack pointer”, or SP for short.
• Initially, the stack is empty, so the stack pointer should be assigned
the value of 0.
5.2.4 Push

void push(int value) { the function that places a value onto the stack.
stack[SP++] = value;
}
int pop(void) { the function to take a value off the stack.
return stack[--SP];
}
#include <iostream>
using namespace std;
int stack[100]; 5.2.6 The stack in action
int SP = 0; 1. imagine that you’ve accidentally written something
void push(int value) {

the more disadvantages we discover.


like this: SP = 100;
stack[SP++] = value; } 2. it may happen that one day you need more than one
int pop(void) { stack;– you’ll have to create another vector for the
return stack[--SP]; } stack’s storage, another stack pointer for a new
vector, probably more push and pop functions too;
int main(void) { 3. it may also happen that you need not
push(3); only push and pop functions, but also some other
push(2); things; you can implement them but try to imagine
push(1); what’ll happen when you have dozens of separately
cout << pop() << endl; implemented stacks
cout << pop() << endl; 4. we’ve used the int stack so far, but you may want to
use the stacks defined for other types: floats, strings
cout << pop() << endl; or even arrays and structures; what’ll happen then?
return 0; }
The objective approach
The objective approach provides solutions for each of these problems.

1. the ability to hide (protect) selected values against unauthorized access is


called encapsulation; the encapsulated values can be neither accessed nor
modified if you want to use them exclusively
2. when you have a class implementing all the needed stack behaviours, you can
produce as many stacks as you want; you don’t need to copy or replicate any
part of the code
3. the ability to enrich the stack with new functions comes from the inheritance;
you can create a new class (or more precisely a subclass) which inherits all the
existing traits from the superclass and adds some new ones.
4. you can create a template which is a generalized, parameterized class, ready
to materialize itself in many different incarnations; its code can adapt to
varying requirements and, for example, create stacks ready to work with other
types of data
5.2.9 Stack from scratch (2)
• We wanted to encapsulate both
variables and make them inaccessible
from the outside world.
• This kind of data is called private in
object programming. class Stack {
• you don’t need to use private:
the private keyword at this point. It’s int stackstore[100];
assumed as default when no other
option is implicitly specified. int SP;
};
class Stack {
private: 5.2.10 Stack from scratch (3)
int stackstore[100];
int SP; both functions access the class variables without any obstacles.

public: The function may be described in two


void push(int value); different way :
• inside the class, when the class body
int pop(void) { contains a full implementation of the
return stackstore[--SP]; method
• outside the class, when the body contains
} only the function header; the function body
is placed outside the class
};
void Stack::push(int value) {
stackstore[SP++] = value;
}
The name should be qualified using the home class name and the “::” operator.
If you omit the qualifying prefix, the function won’t be considered a part of the class. It’ll be an ordinary function instead.
class Stack {
private:
int stackstore[100];
5.2.11 Stack from scratch (4)
int SP; • We have to add another function to our
class. It’s a very specialized function
public: invoked implicitly every time a new
Stack(void) { SP = 0; } stack is created. We call it a
“constructor” because it’s responsible
void push(int value); for the proper construction of each
int pop(void) { new object of the class.
return stackstore[--SP]; • Unfortunately, we can’t name this
function any way we want.. It must be
} named the same as its home class. the
}; constructors aren’t real functions. They
don’t have any return type – not even
void Stack::push(int value) { void.
stackstore[SP++] = value;
}
#include <iostream>
using namespace std;
5.2.13 Stack from scratch (6)
int main(void) {
Stack little_stack, another_stack, funny_stack;

little_stack.push(1);
another_stack.push(little_stack.pop() + 1);
funny_stack.push(another_stack.pop() + 2);
cout << funny_stack.pop() << endl;
return 0;
}
Try to modify the code and add a line like this to the main functions:
little_stack.SP++;
5.2.14 Stack from scratch (7)
We want a new class to handle stacks. We want the new class to be able
to evaluate a sum of all the elements currently stored on the stack.
We don’t want to modify the previously defined stack. We want a new
stack with new capabilities. In other words, we want to construct
a subclass of the Stack class.
class AddingStack : Stack{ };
The class doesn’t define any new component yet, but that doesn’t mean
that it’s empty. It derives all the components defined by its superclass –
the name of the superclass is written after the colon directly after the new
class name.
Any object of the AddingStack class can do everything that
each Stack class’ object does.
class AddingStack : Stack {
private: 5.2.15 Stack from scratch (8)
int sum; 1. We want the push function not only
public: to push the value onto the stack, but
also to add the value to
void push(int value); the sum variable
int pop(void); };
void AddingStack::push(int value) { 2. We want the pop function not only
sum += value; to pop the value off the stack, but
also to subtract the value from
Stack::push(value);} the sum variable
int AddingStack::pop(void) {
int val = Stack::pop(): There’s another thing that should be taken into consideration,
it’s about the initial value of the sum variable.
sum -= val;
return val; } AddingStack::AddingStack(void) : Stack() {
int AddingStack::getSum(void) { sum = 0;
return sum; } } Note the phrase “: Stack()”. It’s a request to invoke the superclass
constructor before the current constructor starts its work.
#include <iostream>
using namespace std;
5.2.21 Stack from scratch (14)
int main(void) {
AddingStack super_stack;
for(int i = 1; i < 10; i++)
super_stack.push(i);
cout << super_stack.getSum() << endl;
for(int i = 1; i < 10; i++)
super_stack.pop();
cout << super_stack.getSum() << endl;
return 0;
}
5.3 Anatomy of the class
class A {
5.3.1 Class components Type Var;
};
A class is an aggregate consisting of variables (also
called fields or properties) and functions
(sometimes called methods). Both variables and should be read as:
functions are class components.
class A {
class Class { private:
int value; Type Var;
all three components
void setVal(int value); are private. };
int getVal(void);
};
5.3.2 Access specifiers
The setVal and getVal components class Class {
are public – they’re accessible to
all users of the class.
public:
The value component is private – void setVal(int value);
it’s accessible only within the class. int getVal(void);
private:
int value;
};
5.3.3 Creating an object
Class the_object;
Any object of the class is equipped with all the components defined in
the class. This means that the_object object has the same three
components as its base class.

the_object.setVal(0);
the_object.value = 0;
5.3.5 "this" pointer
each object is equipped with a special component, its name is this: it’s a pointer to the
current object – each object has its own copy of the this pointer

class Class { class Class {


public: public:
void setVal(int value) { void setVal(int value) {
Class::value = value; this -> value = value;
} }
int getVal(void); value = value; int getVal(void);
private: If any function introduces an entity of the private:
name identical to any of the class components,
int value; the name of the class component is int value;
overridden. It can be accessed only by the
}; qualification with the home class name. };
The general rule
• if S is a structure or class and S has a component named C and

• if p is a pointer to a structure of type S

• then the C component may be accessed in the two following ways:

• (*p).C // p is explicitly dereferenced in order to access the C component


• p->C // p is implicitly dereferenced in order to access the C component
5.3.7 Qualifying component names (2)

Class function names may be overloaded just like ordinary function


names. The default parameter values may be used too.
class Class {
public:
void setVal(int value) { this -> value = value; }
void setVal(void) { value = -2; }
int getVal(void) { return value; }
private:
int value;
};
5.3.9 Overloading constructor names (1)
class Class {
public:
Class(void) { this -> value = -1; }
Constructors may be overloaded Class(int val) { this -> value = val; }
too, depending on specific needs
and requirements void setVal(int value) { this -> value = value; }
int getVal(void) { return value; }
private:
int value;
};
Class object1, object2(100);
cout << object1.getVal() << endl;
cout << object2.getVal() << endl; -1
100
5.3.10 Overloading constructor names (2)
The class on the right has one one-parameter constructor. This means that the only
allowable form of that class’s object creation must be similar to the following:
Class object(2);
The following form Class object; is not allowed.

class Class {
public:
Class(int val) { this -> value = val; }
void setVal(int value) { this -> value = value; }
int getVal(void) { return value; }
private:
int value;
};
#include <iostream>
using namespace std;
5.3.11 Copying constructors
class Class1 { Note that the keyword const used in the parameter
declaration is a promise that the function won’t attempt
public: to modify the values stored in the referenced object.
Class1(int val) { this -> value = val; }
Class1(Class1 const &source) { value = source.value + 100; }
int value; };
class Class2 { There is a special kind of
public: constructor intended to copy
Class2(int val) { this -> value = val; } one object into another.
int value; }; Constructors of this kind have
int main(void) {
one parameter referenced to
Class1 object11(100), object12 = object11;
an object of the same class
Class2 object21(200), object22 = object21;
cout << object12.value << endl;
and are used to copy all
cout << object22.value << endl; important data from the
return 0; source object to the newly
200
} 200
created object
What is a memory leak in C++? a leaky faucet

• A memory leak occurs when a piece (or pieces) of memory that was
previously allocated by a programmer is not properly deallocated by
the programmer. Even though that memory is no longer in use by the
program, it is still “reserved”, and that piece of memory can not be
used by the program until it is properly deallocated by the
programmer. That’s why it’s called a memory leak – because it’s like a
leaky faucet in which water is being wasted, only in this case it’s
computer memory. void memLeak( )
• Here is an example of a memory leak in C++: {
int *data = new int;
*data = 15;
}
#include <iostream>
using namespace std; 5.3.12 Memory leaks
class Class {
The object variable is an example of an “automatic variable”.
public: This means that the variable automatically finishes its life when the
Class(int val) { execution of the function containing the variable’s declaration ends.
value = new int[val];
cout << "Allocation (" << val << ") done." << endl;
} We can imagine that object creation consists
int *value; of two phases:
};
1. the object itself is created and a part of
void MakeALeak(void) { the memory is implicitly allocated to the
Class object(1000); object.
}
int main(void) { 2. the constructor explicitly allocates
MakeALeak();
another part of the memory
return 0;
}
5.3.13 Destructors
We can safeguard ourselves against this danger by defining a special function
called destructor. Destructors have the following restrictions:
• if a class is named X, its destructor is named ~X
• a class can have no more than one destructor
• a destructor must be a parameter-less function (note that the two last
restrictions are the same – can you explain why?)
• a destructor shouldn’t be invoked explicitly
#include <iostream>
using namespace std; 5.3.13 Destructors
class Class {
public:
Class(int val) {
value = new int[val];
cout << "Allocation (" << val << ") done." << endl; }
~Class(void) {
delete [] value;
cout << "Deletion done." << endl; }
int *value;
};
void MakeALeak(void) {
Class object(1000); }
int main(void) {
MakeALeak(); Allocation (1000) done.
Deletion done.
return 0; }
5.4 Static components
#include <iostream>
using namespace std;
5.4.1 The “auto” keyword (1)
void fun(void) {
The “auto” keyword came from the
auto int var = 99; ancestor of “C++”, the “C” programming
cout << "var = " << ++var << endl; language. The word has preserved its
original meaning.
} All the variables in your code belong to
int main(void) { one of two categories. They are:
1. automatic variables, created and
for(int i = 0; i < 5; i++) destroyed, sometimes repeatedly,
and automatically (hence their name)
fun(); during program execution.
return 0; 2. static variables, existing
continuously during the whole program
} var = 100 execution.
var = 100
var = 100
var = 100
var = 100
#include <iostream>
5.4.2 The “static” keyword (2)
using namespace std;
void fun(void) { • The code behaviour has been changed
static int var = 99; radically. The “var” variable is created
cout << "var = " << ++var << endl; and initiated once during the so-called
“program prologue” and is destroyed
} after program completion during the
int main(void) { operation of the so-called “program
epilogue”.
for(int i = 0; i < 5; i++)
fun(); • This means that the var variable exists
even when the fun function isn’t
return 0; var = 100
var = 101
working, so the variable’s value is
} var = 102
preserved between
var = 103 subsequent fun invocations.
var = 104
5.4.3 Instances of the class
Every object created from a particular class is
named a class’s instance. From this point of view,
#include <iostream> each instance of the class is a separate
using namespace std; universe and has nothing to do with any of the
class Class { remaining instances.
public:
int val;
void print(void) { cout << val << endl; }
};
int main(void) {
Class::val = 0;
is wrong and will cause a compilation error.
Class::print();
return 0; None of these components really exist until the
} val and print are non-static first instance is created. In consequence, we
mustn’t use any of the class components until
components of the class we’ve created an object of that class.
#include <iostream>
using namespace std; 5.4.4 Static components of the class
class Class {
static variables are not actually part of any object.
public:
static int Static;
int NonStatic; the variable NonStatic has to have both an
void print(void) { explicitly expressed separate definition and
cout << "Static = " << ++Static << a possible initialization, and both must be
placed outside the class definition.
", NonStatic = " << NonStatic << endl; ---------------------------------------------
} the definition has to be separate from the class body
}; because static variables are not actually part of any
int Class::Static = 0; Removing this line generates an error. object.
int main(void) {
Class instance1, instance2;
instance1.NonStatic = 10; • A static component exists throughout
the whole life of the program.
instance2.NonStatic = 20; Moreover, there is always only one
instance1.print(); component regardless of the number of
instances of the class.
instance2.print();
Static = 1, NonStatic = 10
• We can say that all the instances share
return 0; the same static components.
} Static = 2, NonStatic = 20
The unique traits of the static class variables predestine them to be used as counters of
instances of a particular class.

#include <iostream>
using namespace std;
5.4.5 Static class variables (1)
We’ll increment the Counter inside the Class constructor
class Class { and decrement it inside the Class destructor.
public:
static int Counter; int main(void) {
Class(void) { ++Counter; }; Class a;
~Class(void) { Class b;
--Counter; cout << Class::Counter << " instances so far"
if(Counter == 0) cout << "Bye, bye!" << endl;
<< endl; Class c;
}; Class d;
d.HowMany(); 2 instances so far
void HowMany(void) { cout << Counter << " 4 instances
instances" << endl; } return 0; Bye, bye!
}; }
int Class::Counter = 0; the Counter field is accessed directly when it’s being used inside the
class and with the “::” operator when it’s being used outside the class.
#include <iostream> 5.4.6 Static class variables (2)
using namespace std;
class Class { there are no obstacles to making a particular variable private and
static at the same time. This will obviously prevent direct access to
static int Counter; the variable
public:
Class(void) {
++Counter; int main(void) {
}; Class a;
~Class(void) { --Counter; if(Counter == 0) Class b;
cout << b.HowMany();
"Bye, bye!" << endl; Class c;
}; Class d;
void HowMany(void) { cout << Counter d.HowMany();
<< " instances" << endl; } return 0;
}; } 2 instances
Class::Counter = 1;
int Class::Counter = 0; are strictly prohibited.
4 instances
Bye, bye!
we want to protect the value against any unauthorized modification.
#include <iostream>
using namespace std; 5.4.7 Static class variables (3)
class Class {
It’s not only class variables that can be declared as
static int Counter; static – functions can be declared like this, too.
public:
Class(void) {
++Counter; int main(void) {
}; Class::HowMany();
~Class(void) { Class a; 0 instances
--Counter; Class b; 2 instances
4 instances
if(Counter == 0) b.HowMany(); Bye, bye!
cout << "Bye, bye!" << endl; Class c;
}; Class d;
static void HowMany(void) { d.HowMany();
cout << Counter << " instances" << endl; } return 0;
}; }
int Class::Counter = 0; that the static function may be invoked from inside the class, like this: HowMany();
or by using any of the existing instances, like this: b.HowMany();
5.4.8 Static vs. non-static components

accessed component

static non-static
accessing static OK FAIL
component non-static OK OK
5.5 Objects vs. pointers and objects inside the
objects
5.5.1 Pointers to objects
• So far we’ve treated objects like ordinary variables and assumed that an object is created in the
place where it is declared and destroyed when its declaration scope is exited. This is only one of
the many possible object incarnations.
• Objects may also exist as dynamically created and destroyed entities. In other words, objects may
appear on demand – when they’re needed – and vanish in the same way.

#include <iostream>
using namespace std; int main(void) {
class Class { Class *ptr;
public:
Class(void) { ptr = new Class();
cout << "Object constructed!" << endl;} delete ptr;
~Class(void) { return 0;
cout << "Object destructed!" << endl;} }
};
Object constructed!
Object destructed!
5.5.3. Pointers to functions
Member functions invoked for an object accessed through the
#include <iostream> pointer have to be accessed using the arrow operator, too.
using namespace std;
class Class {
public:
Class(void) { int main(void) {
cout << "Object constructed!" << endl; Class *ptr;
}
~Class(void) { ptr = new Class;
cout << "Object destructed!" << endl; ptr -> value = 1;
} ptr -> IncAndPrint();
void IncAndPrint(void) { delete ptr;
cout << "value = " << ++value << endl; return 0; Object constructed!
} } 2
int value; Object destructed!
};
#include <iostream>
using namespace std; 5.5.4 Selecting the constructor
class Class {
public:
Class(void) { cout << "Object constructed (#1)" << endl; }
Class(int v) { value = v; cout << "Object constructed (#2)" << endl; }
~Class(void) { cout << "Object destructed! val = " << value << endl; }
void IncAndPrint(void) { int main(void) {
cout << "value = " << ++value << endl; Class *ptr1, *ptr2;
} Object constructed (#1) ptr1 = new Class;
Object constructed (#2) ptr2 = new Class(2);
int value; value = 2 ptr1 -> value = 1;
value = 3
}; Object destructed! val = 3
ptr1 -> IncAndPrint();
ptr2 -> IncAndPrint();
Object destructed! val = 2
delete ptr2;
If a class has more than one constructor, one of them may be chosen during object delete ptr1;
creation. This is done by specifying the form of the parameter list associated with return 0;
the class name. }
#include <iostream> 5.5.5 Arrays of pointers to objects (1)
using namespace std;
The class offers us two methods for accessing the array.
class Array {
int *values; Array of 2 ints constructed.
int size; #1:100
#2:101
public: Array of 2 ints destructed. int main(void) {
Array(int siz) {
Array *arr = new Array(2);
size = siz; values = new int[size];
cout << "Array of " << size << " ints constructed." << endl;
for(int i = 0; i < 2; i++)
}
arr->Put(i, i + 100);
~Array(void) {
for(int i = 0; i < 2; i++)
delete [] values;
cout << "#" << i + 1
cout << "Array of " << size << " ints destructed." << endl;
<< ":" << arr->Get(i) << endl;
delete arr;
}
return 0;
int Get(int ix) { return values[ix]; }
}
void Put(int ix, int val) { values[ix] = val; }
};
#include <iostream> 5.5.6 Arrays of pointers to objects (2)
using namespace std;
int main(void) {
class Array { Array of 2 ints constructed.
Array of 2 ints constructed.
Array *arr[2] =
int *values;
#1:10; #1:11; { new Array(2), new Array(2) };
int size; #2:11; #2:12;
public: Array of 2 ints destructed.
Array of 2 ints destructed.
for(int i = 0; i < 2; i++)
Array(int siz) {
for(int j = 0; j < 2; j++)
size = siz; values = new int[size];
arr[i]->Put(j, j + 10 + i);
cout << "Array of " << size << " ints constructed." << endl;
for(int i = 0; i < 2; i++) {
}
for(int j = 0; j < 2; j++)
~Array(void) {
cout << "#" << i + 1
delete [] values;
<< ":" << arr[i]->Get(j) << "; ";
cout << "Array of " << size << " ints destructed." << endl;
cout << endl;
}
}
delete arr[0];
int Get(int ix) { return values[ix]; }
delete arr[1];
void Put(int ix, int val) { values[ix] = val; }
return 0;
};
There are no obstacles to gathering pointers to objects inside an array. }
#include <iostream> 5.5.7 Objects inside objects (1)
using namespace std; An object of any class may be the field of an object of any other class.
class Element { int main(void) {
int value; Collection coll; coll (visible at the main function level)

public:
int Get(void) { return value; } for(int i = 1; i <= 2; i++)
void Put(int val) { value = val; } coll.Put(i, i + 1);
for(int i = 1; i <= 2; i++)
};
cout << "Element #" << i << " = " << coll.Get(i) << endl;
class Collection { return 0;
Element el1, el2; }
public:
int Get(int elno) { return elno == 1 ? el1.Get() : el2.Get(); }
int Put(int elno, int val) { if(elno == 1) el1.Put(val); else el2.Put(val); }
}; Element #2 = 2
el1 and el2 (visible at the coll object level)
Element #3 = 3
#include <iostream> 5.5.8 Objects inside objects (2)
using namespace std;
The conclusion is: constructors from inner objects (objects stored inside other
class Element { objects) are invoked before the outer object’s constructors start their work.

int value;
public:
Element(void) { cout << "Element constructed!" << endl; }
int Get(void) { return value; }
void Put(int val) { value = val; } int main(void) {
}; Collection coll;
class Collection { return 0;
Element el1, el2; }
public: Element constructed!
Collection(void) { cout << "Collection constructed!" << endl; } Element constructed!
Collection constructed!
int Get(int elno) { return elno == 1 ? el1.Get() : el2.Get(); }
int Put(int elno, int val) { if(elno == 1) el1.Put(val); else el2.Put(val); }
};
#include <iostream> 5.5.9 Objects inside objects (3)
using namespace std; we’ve changed the form of the Element class’ constructor – before it
was a parameter-less function, now it needs one parameter of type int.
class Element {
int value;
public:
Element(int val) { value = val; cout << "Element(" << val << ") constructed!" << endl;
}
int Get(void) { return value; } In constructor 'Collection::Collection()':
void Put(int val) { value = val; } error: no matching function for call to 'Element::Element()'
}; The constructor invoked implicitly (sometimes called the default
class Collection { constructor) is the one which has no parameters.

Element el1, el2;


public:
int main(void) {
Collection(void) { cout << "Collection constructed!" << endl; }
Collection coll;
int Get(int elno) { return elno == 1 ? el1.Get() : el2.Get(); }
return 0;
int Put(int elno, int val) { if(elno == 1) el1.Put(val); else el2.Put(val); }
}
};
5.5.10 Objects inside objects (4)
If we want a constructor other than the default one to be invoked during the
creation of an object which is part of another object, we should use this
syntax.
we can present it in the following schematic way:
Class(…) : inner_field_constr1(…), inner_field_constr2(…) { … }
This means that you have to list all the inner objects’ constructors that you
wish to use instead of the default constructors.
This is expressed in the line saying:
Collection(void) : el2(2), el1(1) { … }
#include <iostream>
using namespace std; 5.5.10 Objects inside objects (4)
class Element { the inner constructors have been invoked in the sequence reflecting the order of
the declaration inside the Collections class (el1 first), not in the order in which the
int value; constructors were listed in the Class constructor header (el2 first).
public:
Element(int val) {
value = val; cout << "Element(" << val << ") constructed!" << endl;
}
int Get(void) { return value; }
void Put(int val) { value = val; } int main(void) {
}; Collection coll;
Element(1) constructed!
class Collection { return 0;
Element(2) constructed!
Element el1, el2; Collection constructed! }
public:
Collection(void) : el2(2), el1(1) { cout << "Collection constructed!" << endl; }
int Get(int elno) { return elno == 1 ? el1.Get() : el2.Get(); }
int Put(int elno, int val) { if(elno == 1) el1.Put(val); else el2.Put(val); }
};
class X { Note
public:
X(int x) { }; when the constructor is divided between the
declaration and the definition, the list of alternative
constructors should be associated with the definition,
}; not the declaration.
class Y { This means that the following snippet is correct:
X x;
public:
Y(int x);
};
Y::Y(int x) : x(1) { };
Quiz

CPA: Module 5 Quiz


This quiz will help you prepare for Module 5 Test. You will
have 25 minutes to answer 10 questions. Click Start Quiz to
begin. Good luck!
Q1
//What is the output of the following
program?
#include <iostream>
using namespace std;
class A {
int a;
};
int rnain(void) {
A a;
a.a = 1/2 ;
cout << a.a << er.dl
return 0;
}
//What is the output of the following program?
Q2
#include <iostream>
using namespace std;
class A {
int a;
public:
int b;
A(void) { a = b = 1; }
};
int main(void) {
A a;
a.b /= 2 ;
cout << a.b << endl;
return 0;
}
//What is the output of the following program?
#include <iostream>
using namespace std; Q3
class A {
int a;
public:
A(void) { a = 1; }
int b(void) { return ++a; }
};
int main(void) {
A a;
a.b () ;
cout << a.b() << endl;
return 0;
}
//What is the output of the following program?
#include <iostream>
using namespace std;
Q4
class A {
public:
A() { a[0] = 1; a[1] = 0; }
int a[2];
int b(void) { int x=a[0]; a[0]=a[1]; a[1]=x;
return x;}
};
int main(void) {
A a; a.b();
cout << a.b();
cout << a.a[1] << endl;
return 0;
}
//What is the output of the following program?
#include <iostream>
using namespace std; Q5
class A {
public:
A() { a.a = a.b = 1; }
struct { int a,b; } a;
int b(void);
};
int A::b(void) { int x=a.a; a.a=a.b; a.b=x; return x;}

int main(void) {
A a;
a. a. a = 0; a.b();
cout << a.b();
cout << a.a.b << endl;
return 0;
}
//What is the output of the following
program?
#include <iostream> Q6
using namespace std;
class A {
public :
int a;
A() { a = 1; }
A(int aa) { a = 2; }
A (A &aa) { a = 3; }
};
int main(void) {
A a(1),b(a);
cout << a.a + b.a << endl;
return 0;
}
//What is the output of the following program?
#include <iostream>
using namespace std;
int z = 1;
Q7
class A {
public :
int a ;
A() { a = 1; z++; }
A (A &aa) { a = 3; z++; }
~A ( ) { z--; }
};
void fun(void) {
A a, b (a) , c (b) ;
}
int main (void) {
cout << z << endl;
return 0;
}
//What is the output of the following
program?
#include <iostream> Q8
using namespace std;
class A {
public:
static int a;
A() { a = 1; a++; }
A (A &aa) { a++; }
};
int main (void) {
A a, b (a) , c (b) ;
cout << A.a << endl;
return 0;
}
//What is the output of the following
program?
#include <iostream> Q9
using namespace std;
class A {
public:
static int a;
A() { a = 0; a++; }
A (A &Saa) { a++; }
};
int A::a = 1;
int main(void) {
A a,b(a),c (b);
cout << a.a << endl;
return 0;
}
//What is the output of the follovving program?
#include <iostream>
using namespace std;
class A {
Q10
public :
int a;
A() { a = 0; }
A(int b) { a = b + 1; }
};
class B {
public :
A a;
B () : a (0) { }
};
int main(void) {
B *b = new B() ;
cout << b->a.a << endl;
return 0;
}
ASSESSMENT
Assessment
What happens when you attempt to compile and run the following code?
#include <iostream>
using namespace std; Q1
class A {
int data[3];
public:
int cnt;
void put(int v) {data[cnt++] = v; }
}; Select correct answer (single
int main() { choice)
A a; ○ Compilation fails
a.cnt = 0; ○ It prints 0
a.put(1);
a.put(1);
○ It prints 1
cout << a.cnt; ○ It prints 2
return 0;
}
2
What happens when you attempt to compile and run the following code?
#include <iostream>
using namespace std;
class A {
Q2
int cnt;
void put(int v) { cout << cnt++;}
}; Select correct answer (single choice)
int main() { ○ Compilation fails
A a; ○ It prints 0
a.cnt =0; ○ It prints 1
a.put(1); ○ It prints 2
a.put(1);
return 0;
}
err
What happens when you attempt to compile and run the following code?
#include <iostream> Q3
using namespace std;
class A {
public:
int cnt;
void put(int v);
Select correct answer (single choice)
};
○ Compilation fails
void A::put(int v) {cout << ++cnt; }
○ It prints 0
int main() {
○ It prints 1
A a[2];
○ It prints 2
a[0].cnt = 0; a[1].cnt = 1;
a[a[0].cnt].put(a[1].cnt);
return 0;
}
1
What happens when you attempt to compile and run the following code
#include <iostream>
Q4
using namespace std;
class A {
public:
float v;
float set(float v) { A::v += 1.0; return v; }
float set(void) { A::v = v + 1.0; return 0.0; }
float get(float v) { v+=A::v; return v;}
}; Select correct answer (single choice)
int main() { ○ Compilation fails
A a; ○ It prints 1
cout << a.get(a.set(a.set(a.set()))); ○ It prints 2
return 0; ○ It prints 3
3
}
What happens when you attempt to compile and run the following code?
#include <iostream>
using namespace std; Q5
class A {
public:
A() {v = 2.5;}
float v;
float set(float v) { A::v += 1.0; return v;}
float get(float v) { v+= A::v; return v;}
};
int main() { Select correct answer (single choice)
A a; ○ Compilation fails
a.A(); ○ It prints 1
cout << a.get(a.set(1. 5)); ○ It prints 5
return 0; ○ It prints 3
} err
What happens when you attempt to compile and run the following code?
#include <iostream> Q6
using namespace std;
class A {
public:
A() {v = 2.5;}
float v;
float set (float v) { A::v += 1.0; return v;}
float get(float v) { v += A::v; return v;}
};
Select correct answer (single choice)
int main() {
○ Compilation fails
A a;
○ It prints 1
cout << a.get(a.set(1.5));
○ It prints 5
return 0;
○ It prints 3
}
5
What happens when you attempt to compile and run the following code?
#include <iostream>
using namespace std; Q7
class A {
public:
A() {v = 2.5;}
A(float v) {A::v = v + 1.0; }
float v;
float set(float v) {A::v+= 1.0; return v;}
float get(float v) { v += A::v; return v;}
}; Select correct answer (single choice)
int main() { ○ Compilation fails
A a,b(1.0); ○ It prints 1
cout << a.get(b.set(1.5)); ○ It prints 2
return 0; ○ It prints 4
} 4
What happens when you attempt to compile and run the following code?
#include <iostream>
using namespace std; Q8
class A {
public:
A(A &a) {v = a.get(0.0); }
A(float v) {A::v= v;}
float v;
float set(float v) {A::v += v; return v;}
float get(float v) { return A::v + v;}
}; Select correct answer (single choice)
int main() { ○ Compilation fails
A *a = new A(1.0), *b = new A(*a); ○ It prints 1
cout << a->get(b->set(a->v)); ○ It prints 2
return 0; ○ It prints 4
} 2
What happens when you attempt to compile and run the following code?
#include <iostream>
using namespace std;
Q9
class A {
public:
A(A *v) {A::v = v; }
A(){A::v=1.0;}
float v;
float set(float v) { A::v = v; return v;}
float get(float v) { return A::v;}
}; Select correct answer (single choice)
int main(){ ○ Compilation fails
A a,*b = new A(a); ○ It prints 1
cout << a->get(b->set(a->v)); ○ It prints 2
return 0; ○ It prints 4
}
What happens when you attempt to compile and run the following code?
#include <iostream> Q10
using namespace std; int main() {
class A { B b(2.0);
public: cout << b.b;
float v; return 0;
A(float x) : v(x) {} }
};
class B {
public: Select correct answer (single choice)
A a; ○ Compilation fails
float b; ○ It prints 1
B(float x) : a(x + 1) { b = a.v;} ○ It prints 2
}; ○ It prints 3
3

You might also like