Vous êtes sur la page 1sur 11

Friendship and inheritance in Object Oriented Programming with C++

Friend functions
In principle, private and protected members of a class cannot be accessed from outside the same
class in which they are declared. However, this rule does not apply to "friends".

Friends are functions or classes declared with the friend keyword.

A non-member function can access the private and protected members of a class if it is declared
a friend of that class. That is done by including a declaration of this external function within the
class, and preceding it with the keyword friend:

1 // friend functions 24
2 #include <iostream>
3 using namespace std;
4
5 class Rectangle {
6 int width, height;
7 public:
8 Rectangle() {}
9 Rectangle (int x, int y) : width(x), height(y) {}
10 int area() {return width * height;}
11 friend Rectangle duplicate (const Rectangle&);
12 };
13
14 Rectangle duplicate (const Rectangle& param)
15 {
16 Rectangle res;
17 res.width = param.width*2;
18 res.height = param.height*2;
19 return res;
20 }
21
22 int main () {
23 Rectangle foo;
24 Rectangle bar (2,3);
25 foo = duplicate (bar);
26 cout << foo.area() << '\n';
27 return 0;
28 }

The duplicate function is a friend of class Rectangle. Therefore, function duplicate is able
to access the members width and height (which are private) of different objects of type
Rectangle. Notice though that neither in the declaration of duplicate nor in its later use in
main, function duplicate is considered a member of class Rectangle. It isn't! It simply has
access to its private and protected members without being a member.
Typical use cases of friend functions are operations that are conducted between two different
classes accessing private or protected members of both.

Inheritance between classes

Classes in C++ can be extended, creating new classes which retain characteristics of the base
class. This process, known as inheritance, involves a base class and a derived class: The derived
class inherits the members of the base class, on top of which it can add its own members.

For example, let's imagine a series of classes to describe two kinds of polygons: rectangles and
triangles. These two polygons have certain common properties, such as the values needed to
calculate their areas: they both can be described simply with a height and a width (or base).

This could be represented in the world of classes with a class Polygon from which we would
derive the two other ones: Rectangle and Triangle:

The Polygon class would contain members that are common for both types of polygon. In our
case: width and height. And Rectangle and Triangle would be its derived classes, with
specific features that are different from one type of polygon to the other.

Classes that are derived from others inherit all the accessible members of the base class. That
means that if a base class includes a member A and we derive a class from it with another
member called B, the derived class will contain both member A and member B.

The inheritance relationship of two classes is declared in the derived class. Derived classes
definitions use the following syntax:

class derived_class_name: public base_class_name

{ /*...*/ };

Where derived_class_name is the name of the derived class and base_class_name is the name
of the class on which it is based. The public access specifier may be replaced by any one of the
other access specifiers (protected or private). This access specifier limits the most accessible
level for the members inherited from the base class: The members with a more accessible level
are inherited with this level instead, while the members with an equal or more restrictive access
level keep their restrictive level in the derived class.

1 // derived classes 20
2 #include <iostream> 10
3 using namespace std;
4
5 class Polygon {
6 protected:
7 int width, height;
8 public:
9 void set_values (int a, int b)
10 { width=a; height=b;}
11 };
12
13 class Rectangle: public Polygon {
14 public:
15 int area ()
16 { return width * height; }
17 };
18
19 class Triangle: public Polygon {
20 public:
21 int area ()
22 { return width * height / 2; }
23 };
24
25 int main () {
26 Rectangle rect;
27 Triangle trgl;
28 rect.set_values (4,5);
29 trgl.set_values (4,5);
30 cout << rect.area() << '\n';
31 cout << trgl.area() << '\n';
32 return 0;
33 }

The objects of the classes Rectangle and Triangle each contain members inherited from
Polygon. These are: width, height and set_values.

The protected access specifier used in class Polygon is similar to private. Its only difference
occurs in fact with inheritance: When a class inherits another one, the members of the derived
class can access the protected members inherited from the base class, but not its private
members.

By declaring width and height as protected instead of private, these members are also
accessible from the derived classes Rectangle and Triangle, instead of just from members of
Polygon. If they were public, they could be accessed just from anywhere.
We can summarize the different access types according to which functions can access them in
the following way:

Access public protected private


members of the same class yes yes yes
members of derived class yes yes no
not members yes no no

Where "not members" represents any access from outside the class, such as from main, from
another class or from a function.

In the example above, the members inherited by Rectangle and Triangle have the same access
permissions as they had in their base class Polygon:
1 Polygon::width // protected access
2 Rectangle::width // protected access
3
4 Polygon::set_values() // public access
5 Rectangle::set_values() // public access

This is because the inheritance relation has been declared using the public keyword on each of
the derived classes:

class Rectangle: public Polygon { /* ... */ }

This public keyword after the colon (:) denotes the most accessible level the members inherited
from the class that follows it (in this case Polygon) will have from the derived class (in this case
Rectangle). Since public is the most accessible level, by specifying this keyword the derived
class will inherit all the members with the same levels they had in the base class.

With protected, all public members of the base class are inherited as protected in the derived
class. Conversely, if the most restricting access level is specified (private), all the base class
members are inherited as private.

For example, if daughter were a class derived from mother that we defined as:

class Daughter: protected Mother;


This would set protected as the less restrictive access level for the members of Daughter that it
inherited from mother. That is, all members that were public in Mother would become
protected in Daughter. Of course, this would not restrict Daughter from declaring its own
public members. That less restrictive access level is only set for the members inherited from
Mother. If no access level is specified for the inheritance, the compiler assumes private for
classes declared with keyword class and public for those declared with struct.
Actually, most use cases of inheritance in C++ should use public inheritance. When other access
levels are needed for base classes, they can usually be better represented as member variables
instead.

What is inherited from the base class?


In principle, a publicly derived class inherits access to every member of a base class except:

its constructors and its destructor


its assignment operator members (operator=)
its friends
its private members

Even though access to the constructors and destructor of the base class is not inherited as such,
they are automatically called by the constructors and destructor of the derived class.

Unless otherwise specified, the constructors of a derived class call the default constructor of its
base classes (i.e., the constructor taking no arguments). Calling a different constructor of a base
class is possible, using the same syntax used to initialize member variables in the initialization
list:

derived_constructor_name (parameters) : base_constructor_name (parameters)


{...}

For example:

1 // constructors and derived classes Mother: no parameters


2 #include <iostream> Daughter: int parameter
3 using namespace std;
4 Mother: int parameter
5 class Mother { Son: int parameter
6 public:
7 Mother ()
8 { cout << "Mother: no parameters\n"; }
9 Mother (int a)
10 { cout << "Mother: int parameter\n"; }
11 };
12
13 class Daughter : public Mother {
14 public:
15 Daughter (int a)
16 { cout << "Daughter: int parameter\n\n"; }
17 };
18
19 class Son : public Mother {
20 public:
21 Son (int a) : Mother (a)
22 { cout << "Son: int parameter\n\n"; }
23 };
24
25 int main () {
26 Daughter kelly(0);
27 Son bud(0);
28
29 return 0;
30 }
31
32
33
34

Notice the difference between which Mother's constructor is called when a new Daughter object
is created and which when it is a Son object. The difference is due to the different constructor
declarations of Daughter and Son:

1 Daughter (int a) // nothing specified: call default constructor


2 Son (int a) : Mother (a) // constructor specified: call this specific
constructor

Operator Overloading in C++


Operator Overloading

Operator overloading is an important concept in C++. It is a type of polymorphism in which an


operator is overloaded to give user defined meaning to it. Overloaded operator is used to perform
operation on user-defined data type. For example '+' operator can be overloaded to perform
addition on various data types, like for Integer, String(concatenation) etc.

Almost any operator can be overloaded in C++. However there are few operator which can not
be overloaded. Operator that are not overloaded are follows

scope operator - ::
sizeof
member selector - .
member pointer selector - *
ternary operator - ?:

Operator Overloading Syntax


Implementing Operator Overloading

Operator overloading can be done by implementing a function which can be :

Member Function
Non-Member Function
Friend Function

Operator overloading function can be a member function if the Left operand is an Object of that
class, but if the Left operand is different, then Operator overloading function must be a non-
member function.

Operator overloading function can be made friend function if it needs access to the private and
protected members of class.

Restrictions on Operator Overloading

Following are some restrictions to be kept in mind while implementing operator overloading.

Precedence and Associativity of an operator cannot be changed.


Arity (numbers of Operands) cannot be changed. Unary operator remains unary, binary
remains binary etc.
No new operators can be created, only existing operators can be overloaded.
Cannot redefine the meaning of a procedure. You cannot change how integers are added.

Example: overloading '+' Operator to add two time object

#include< iostream.h>
#include< conio.h>
class time
{
int h,m,s;
public:
time()
{
h=0, m=0; s=0;
}
void getTime();
void show()
{
cout<< h<< ":"<< m<< ":"<< s;
}
time operator+(time); //overloading '+' operator
};
time time::operator+(time t1) //operator function
{
time t;
int a,b;
a=s+t1.s;
t.s=a%60;
b=(a/60)+m+t1.m;
t.m=b%60;
t.h=(b/60)+h+t1.h;
t.h=t.h%12;
return t;
}
void time::getTime()
{
cout<<"\n Enter the hour(0-11) ";
cin>>h;
cout<<"\n Enter the minute(0-59) ";
cin>>m;
cout<<"\n Enter the second(0-59) ";
cin>>s;
}
void main()
{
clrscr();
time t1,t2,t3;
cout<<"\n Enter the first time ";
t1.getTime();
cout<<"\n Enter the second time ";
t2.getTime();
t3=t1+t2; //adding of two time object using '+' operator
cout<<"\n First time ";
t1.show();
cout<<"\n Second time ";
t2.show();
cout<<"\n Sum of times ";
t3.show();
getch();
}

File Operations with C++


So far, we have been using the iostream standard library, which provides cin and cout methods
for reading from standard input and writing to standard output respectively.

This tutorial will teach you how to read and write from a file. This requires another standard C++
library called fstream, which defines three new data types:
Data Type Description
ofstream This data type represents the output file stream and is used to
create files and to write information to files.
ifstream This data type represents the input file stream and is used to read
information from files.
fstream This data type represents the file stream generally, and has the
capabilities of both ofstream and ifstream which means it can
create files, write information to files, and read information from
files.

To perform file processing in C++, header files <iostream> and <fstream> must be included in
your C++ source file.

Opening a File

A file must be opened before you can read from it or write to it. Either the ofstream or fstream
object may be used to open a file for writing and ifstream object is used to open a file for reading
purpose only.

Following is the standard syntax for open() function, which is a member of fstream, ifstream, and
ofstream objects.

void open(const char *filename, ios::openmode mode);

Here, the first argument specifies the name and location of the file to be opened and the second
argument of the open() member function defines the mode in which the file should be opened.

Mode Flag Description


ios::app Append mode. All output to that file to be appended to the end.
ios::ate Open a file for output and move the read/write control to the end of the file.
ios::in Open a file for reading.
ios::out Open a file for writing.
ios::trunc If the file already exists, its contents will be truncated before opening the file.

You can combine two or more of these values by ORing them together. For example if you want
to open a file in write mode and want to truncate it in case it already exists, following will be the
syntax:
ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );

Closing a File

When a C++ program terminates it automatically closes flushes all the streams, release all the
allocated memory and close all the opened files. But it is always a good practice that a
programmer should close all the opened files before program termination.
Following is the standard syntax for close() function, which is a member of fstream, ifstream,
and ofstream objects.

Example:
#include <fstream>
#include <iostream>
using namespace std;

int main () {

char data[100];

// open a file in write mode.


ofstream outfile;
outfile.open("afile.dat");

cout << "Writing to the file" << endl;


cout << "Enter your name: ";
cin.getline(data, 100);

// write inputted data into the file.


outfile << data << endl;

cout << "Enter your age: ";


cin >> data;
cin.ignore();

// again write inputted data into the file.


outfile << data << endl;

// close the opened file.


outfile.close();

// open a file in read mode.


ifstream infile;
infile.open("afile.dat");

cout << "Reading from the file" << endl;


infile >> data;

// write the data at the screen.


cout << data << endl;

// again read the data from the file and display it.
infile >> data;
cout << data << endl;

// close the opened file.


infile.close();

return 0;
}

When the above code is compiled and executed, it produces the following sample input and
output:
Writing to the file
Enter your name: Zara
Enter your age: 9
Reading from the file
Zara
9

Above examples make use of additional functions from cin object, like getline() function to read
the line from outside and ignore() function to ignore the extra characters left by previous read
statement.
***

Vous aimerez peut-être aussi