LevSelector.com |
intro - preparing for the interview
If you want to pick up C++ fast, here is a possible plan:
first C++ programs | home - top of the page - |
Some of the examples in this tutorial are original, others are inspired
or derived from www.cprogramming.com/tutorial.html
, from "The Beginner's Guide to C++"
by Oleg Yaroshenko, (BTW, this is a
very VERY good book for a beginner), and other sources.
Also good place is the C/C++ reference: cppreference.com.
1st program
// file hello.cpp
#include <iostream> main() { std::cout<<"Hello" << std::endl; } |
or to avoid typing "std::" every time:
// file hello.cpp #include <iostream> using namespace std; main() { cout<<"Hello" << endl; } |
// file hello2.cpp
#include <iostream> using namespace std; const int ii = 5; // const will not allow to change it int main() {
|
To compile and run on Linux:
c++ -o a hello.cpp
a
hello
On linux there is a main compiler/linker called "gcc" and 2 scripts (today they are executables) called c++ and g++ (they are usually the same). The c++ inside calls gcc with default options and libraries ( -l stdc++ ). So you can cmpile your test as following:
gcc -l stdc++ -o a hello.cpp
On other unixes (Solaris, for example) one can run gcc, or use other compilers (Sun has its own compiler).
On Windows people ususally use Microsoft Visual Studio - just google it and download 3-month free installation. You can also install cygwin - and run unix-like gcc. Or there are some other options:
http://www.mingw.org/ -> gcc for windows
http://www.bloodshed.net/devcpp.html - Bloodshed Dev-C++ is a full-featured IDE for the C/C++ - uses Mingw port of GCC.
http://www.eclipse.org/downloads/ -> eclipse IDE does c++
http://netbeans.org/features/cpp/index.html -> netbeans IDE does c++
http://www.embarcadero.com/products/cbuilder - CodeGear - Borland C++ builder aquired in 2008 by Embarcadero
Yet another option - download free compiler from http://www.borland .com. For version 5.5
it installs into C:\Borland\Bcc55.
Add to path: C:\Borland\Bcc55;C:\Borland\Bcc55\bin
Create 2 cfg files in C:\Borland\Bcc55\bin as advised in the readme file.
now you can compile from command prompt:
bcc32.exe hello.cpp
Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland
hello.cpp:
Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland
hello.exe
Hello
#define
#include <iostream.h>
#define MAMA "mama" <<endl; main() {
|
C++ inherits all standard operators from C, for example:
++a; and
a++;
a + = 2; a - = 2; a* = 4; a* = 5; |
data types | home - top of the page - |
data types:
int, char, long int, float, double, long double,
bool - boolean (2 values: true and false - same as 1 and
0)
cout << sizeof (char); // to show the size
in memory
unsigned modifier
#include <iostream.h> main() { cout << "sizeof(int) : " << sizeof(int) << endl; cout << "sizeof(char) : " << sizeof(char) << endl; cout << "sizeof(long) : " << sizeof(long) << endl; cout << "sizeof(float) : " << sizeof(float) << endl; cout << "sizeof(double) : " << sizeof(double) << endl; cout << "sizeof(long double) : " << sizeof(long double) << endl; } |
auto var1 = 1; // int
auto var2 = 1.0; // double
int var1;
decltype(var1) var2; // declare var2 to be of the same type as var1
Enumerated types:
enum weekDay {Sunday=1, Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday};
// Monday will be 2, Tuesday - 3, etc. weekDay myDay = Monday;
|
Define your own types using the "typedef" statement:
typedef int weekDays[7];
main() { weekDays theDays; // array of 7 elements // ... } |
Type casting:
#include <iostream.h>
int main() { cout<<(char)65; // The (char) is a typecast, telling the computer to interpret the 65 as a // character, not as a number. It is going to give the ASCII output of // the equivalent of the number 65(It should be the letter A). return 0; } #include <iostream.h> //-- 2 forms of typecasting: |
pointers and references | home - top of the page - |
pointers
#include <iostream.h>
int main() { int x; //A normal integer int *pointer; //A pointer to an integer pointer=&x; //Read it, "pointer equals the address of x" cin>>x; //Reads in x cout<<*pointer; //Note the use of the * to output the actual number stored in x return 0; } |
Three ways:
int* a;
int *a;
int * a;
Reference = alias (shortcut)
int A = 0;
int & rA = A; // rA is reference - and we initialized it to be an alias for A rA = 1;
// now rA == 1, which means that A == 1 too.
int * prA = &rA;
// &rA is same as &A
int & rrA = rA;
// one more alias for A
const int & crA = A;
// one more alias
|
Pointers to functions:
void ff(int a, char b); // function itself
void (*ptf)(int a, char b); // pointer to a function
void (*afp[10])(int a, char b); // array of function
pointers
// initializing the pointer and invoking
the function
ptf = ff;
(*ptf)(5,'A');
// same for the array of pointers to functions:
afp[3] = ff;
(*atf)(5,'A');
Far pointers:
int* _far pnum1 = %num1; // windows
Pointers to objects:
class myClass {
// some definitions here } myClass obj1; // object of the type of this class
|
Pointers to pointers:
int** pp;
structures and arrays | home - top of the page - |
structures
#include <iostream.h>
// define structure type
int main() {
structure.Height=12; //
another way to initialize
ptr=&structure; // pointer to
the structure
|
In C++ you can copy structured variables by assigning them (or passing/returning
them into/from a function).
if A,B - structures, and you do one of those:
A = B
*pA = *pB
Then actual shallow copying of a structure members will happen (shallow means
that targets of pointer members will not be followed and copied).
Same shallow copying will happen if we pass the structure to a function. All
this is demonstrated in the text below (it is written in C-style and works in
both C and C++) :
#include <stdio.h>
struct TT { int a; int b; };
void showA(void) { printf(" A.a=%d A.b=%d\n",A.a,A.b); }
void val(struct TT s) {
main () {
printf("B=A:\n"); B = A; showB();
printf("*pB=*pA:\n"); *pB = *pA; showB();
printf("\npassing struct into a function makes a shallow copy\n");
Output: initially:
passing struct into a function makes a shallow
copy
passing struct into a function by pointer
|
arrays
#include <iostream.h>
int main() {
int grid[3][3] = { { 1,2,3 }, { 1,2,3 }, { 1,2,3 } }; // initialize 2-dim array int x, y, anarray[8][8];//declares an array like a chessboard
for(x=0; x<8;x++) {
return 0;
|
*a + 1; //
take value at addr. pointed by a - and increase the value by 1
*(a+1); //
shift the address by the size of one data element (2 bytes for int) - and
take the value there.
#include <iostream.h>
int arr[4] = {1,2,3,4}; int *pp; main () { pp = arr; cout << "Hello" << endl; cout << "arr[2] = " << arr[2] << " = " << *(pp+2) << " = " << *(arr+2) << endl; cout << sizeof(arr)/sizeof(arr[0]); cout << endl; } |
One thing that arrays don't require that other variables do, is a reference
operator.
Example: a pointer to the string :
char *ptr;
char str[40]; ptr=str; //gives the memory address without a reference operator(&) //As opposed to int *ptr;
|
Dynamic arrays:
create and destroy using new and delete [] operators:
#include <iostream.h>
#include <stdio.h> // to use printf( ) void main(void) {
|
logic, if-else, for, while, switch | home - top of the page - |
logic
#include <iostream.h>
main () { cout << ( 0 < 2 ); // 1 cout << (2 != 2 ); // 0 cout << !(1 || 0); // 0 cout << !(1 || 1 && 0); // 0 (AND is evaluated before OR) cout << !((1 || 0) && 0); // 1 (Parenthesis are useful) cout << ( 1 == 1 || 1 != 2); // 1 (Parenthesis are useful) cout << endl;
|
if .. else ..
#include <iostream.h>
int main() { int age; cout<<"Please input your age: "; //Asks for age cin>>age; //The input is put in age if(age<100) { cout<<"You are pretty young!"; } else if(age==100) { cout<<"You are old"; } else if(age>100) { cout<<"You are really old"; } return 0; } |
There exists a goto syntax:
goto part1;
... part1: .... |
for( ; ; )
#include <iostream.h>
void main() { for(int x=0;x<100;x++) { cout<<x<<endl; } return 0; } |
while
#include <iostream.h>
main() { int x=0; while(x<100) { cout<<x<<endl; x++; } } |
do..while
#include <iostream.h>
int main() { int x; x=0; do { cout<<"Hello world!"; }while(x!=0); return 0; } |
break & continue
- used to jump from loops (and nested loops);commands
switch
#include <iostream.h>
#include <conio.h> int main() { int input; cout<<"1. Play game"; cout<<"2. Load game"; cout<<"3. Play multiplayer"; cout<<"4. Exit"; cin>>input; switch (input) { case 1: playgame(); break; case 2: loadgame(); break; case 3: playmultiplayer(); break; case 4: return 0; default: cout<<"Error, bad input, quitting"; } return 0; } |
functions | home - top of the page - |
function
#include <iostream.h>
int mult(int x, int y); // prototype int main() {
int mult(int x, int y) {
|
Simple parameters are passed by value (as in C).
Arrays are passed by pointer (as in C).
For example, these 2 functions are identical:
#include <stdio.h>
void f1(int *ar) {ar[0]=5; ar[1]=6; printf("inside
function\n %d %d\n",ar[0],ar[1]);}
|
New in C++ - passing by reference (alias) using "&" notation in the declaration (as opposed to "*" for pointer). See the table below:
Three types of passing parameters into functions:
passing Object
(make shallow copy) |
Passing Pointer
(explicitly) |
Passing Reference
(aliasing) |
|
Call | f(X) | f(&X) | f(X) |
argument | f(person x) | f(person * x) | f(person & x) |
passing | Object | Pointer | Pointer |
Axess to X
from f( ) body |
none | *x | x |
Example: passing a reference:
#include <iostream.h>
void f (int & x) { x = 2; } void main() { int a=1; cout << a << endl; f(a); cout << a << endl; } |
Use the word "const" when passing an argument to tell the function that it can NOT change it.
You can pass pointers to functions as parameters:
// prototype two functions
void sort1(int* pArr, int n); void sort2(int* pArr, int n); // prototype the function to which we will pass
// declare a pointer
int arr[100] = { ... }; // initialize the array
// now we can work:
|
Example: passing an array of strings:
void showStrings(char* parr[], int Nelements);
// here each element of array contains a pointer
to a string (to a char array).
Note: passing array as a parameter does NOT copy the whole array,
but passes the address. Example:
#include <iostream> void myprint (int arr[], int len) { int main ()
{ |
Function prototype - shows return type, mame, and types of parameters.
No function body. Just to inform the compiler - so that it can process calls
to this function. The actual definition of the function can be placed somewhere
futher down the file.
Example:
double cube(double x);
Inline function: - if function is defined with inline keyword - the compiler may choose to replace the function calls with the actual code from the function. This makes the code run faster - but also increases the size of the code, so be careful. Synax is straightforward:
#include <iostream.h>
inline void hello(void) { cout<<"hello"; } int main() { hello(); return 0; } |
Default Arguments:
You can define default values for function parameters, for example:
void say(int N1=1, int N2=2);
void say(int N1, int N2) {
|
Function overloading - you may have several functions with the same name, but with different parameter lists.
Template function - generic function that can be used
with different data-types. Big libraries of templates exist (example: STL
- Standard Template Library).
working with strings | home - top of the page - |
"This is a static string"
char string[50]; // make last element a '/0' character char ss[] = "ABC"; // will have 4 elements - last will be '\0' cout << sizeof ss; // 4 char ss[] = {'A','B','C','\0'}; // same char ss[] = ""; // contains single char '\0' cout << "A\0BC" << 'D'; // AD , because \0 signifies the end of the string //-------------------
|
Using cin>> to input a string works,
but it will terminate the string after it reads the first space.
The best way to handle this situation is to use the function cin.getline.
Technically cin is a class, and you are calling one of its member functions.
The prototype for that function is:
cin.getline(char *buffer, int length, char terminal_char);
The char *buffer is a pointer to the first element of the character array, so that it can actually be used to access the array. The int length is simply how long the string to be input can be at its maximum (how big the array is). The char terminal_char means that the string will terminate if the user inputs whatever that character is. Keep in mind that it will discard whatever the terminal character is.
It is possible to make a function call of cin.getline(arry, '\n'); without the length, or vice versa, cin.getline(arry, 50); without the terminal character. Note that \n is the way of actually telling the compiler you mean a new line, i.e. someone hitting the enter key.
For a example:
#include <iostream.h>
int main() { char string[256]; //A nice long string cout<<"Please enter a long string: "; cin.getline(string, 256, '\n'); //The user input goes into string cout<<"Your long string was:"<<endl<<string; return 0; } |
String.h is a header file that contains many functions for manipulating strings. One of these is the string comparison function.
int strcmp(const char *s1, const char *s2);
// compares 2 strings, returns negative, zero or positive result
int strcmpi(const char *s1, const char *s2);
// not case sensitive
char *strcat(char *desc, char *src);
// string concatenate
char *strupr(char *s);
// converts to uppercase
char *strlwr(char *s);
// converts to lowercase
size_t strlen(const char *s); // the
length of a string, minus the termating character(\0).
#include <iostream.h> // For cout #include <string.h> // For many of the string functions int main() { char name[50]; char lastname[50]; cout<<"Please enter your name: "; cin.getline(name, 50, '\n'); //Use gets to input strings with spaces or //just to get strings after the user presses enter if(!strcmpi("Alexander", name)) // strcmpi returns 0 for equal strings cout<<"That's my name too."<<endl; } else { cout<<"That's not my name."; } cout<<"What is your name in uppercase..."<<endl;
cout<<"And, your name in lowercase..."<<endl;
cout<<"Your name is "<<strlen(name)<<" letters long"<<endl; //strlen returns the length of the string cout<<"Enter your last name:";
|
text files read/write | home - top of the page - |
Reading/writing text files
C++ has two basic classes to handle files, ifstream (input) and ofstream (output). To use them, include the header file fstream.h.
Declaration:
ifstream a_file;
a_file.open()
a_file.close()
ifstream a_file("filename");
// declare and open the file for input in one command
Because C++ supports overloading operators, it is possible to use <<
and >> in front of the instance of the class as if it were cout or cin.
For example:
#include <fstream.h>
#include <iostream.h> int main() {
// writing to a file
// reading from a file
|
Possible values:
ios::app -- Opens the file,
and allows additions at the end
ios::ate -- Opens the file,
but allows additions anywhere
ios::trunc -- Deletes everything
in the file
ios::nocreate -- Does not
open if the file must be created
ios::noreplace -- Does not
open if the file already exists
Example: reading text file
#include <stdlib.h> // header needed for exit()
#include <fstream.h> int main() {
ifstrearm input ("somefile.txt");
|
binary file read/write | home - top of the page - |
Example: writing/reading a binary file
writing binary | reading binary |
#include <stdlib.h> // header needed
for exit()
#include <fstream.h> int main() {
char text1[80] = "\n\tSome text\n";
output.write((char *) &text1, sizeof(text1));
for (int i=0;i<sizeof(text3);i++) output.put(text3[i]);
|
#include <stdlib.h> // header needed
for exit()
#include <fstream.h> int main() {
char text1[80], text2[80], text3[80]; input.read((char *) &text1, sizeof(text1));
for (int i=0;i<sizeof(text3);i++) input.get(text3[i]);
|
File pointer:
#include <iomanip.h>
long FP = input.tellg(); // get
file pointer
input.seekg(0,ios::beg); // set
file pointer
input.seekg(-,ios::end); // set
file pointer
seekg(), tellg() - set and get the
value of a get pointer
seekp(), tellp() - set and get
the value of a put pointer
Random Access to a File:
fstream myfile;
myfile.open("file_name", ios::app | ios::in
| ios::out | ios::binary);
command line arguments | home - top of the page - |
Accepting command line arguments
int main(int argc, char* argv[])
- // argc - int number of arg values +1 , because argv[0] is full path
name of the program itself
#include <fstream.h> //Needed to manipulate files
#include <iostream.h> #include <io.h> //Used to check file existence int main(int argc, char * argv[]) { if(argc!=2) { cout<<"Correct input is: filename"; return 0; } if(access(argv[1], 00)) //access returns 0 if the file can be accessed { //under the specified method (00) cout<<"File does not exist"; //because it checks file existence return 0; } ifstream the_file; //ifstream is used for file input the_file.open(argv[1]); //argv[1] is the second argument passed in //presumably the file name char x; the_file.get(x); while(x!=EOF) //EOF is defined as the end of the file { cout<<x; the_file.get(x);//Notice we always let the loop check x for the end of } //file to avoid bad output when it is reached the_file.close(); //Always clean up return 0; } |
Example - linked lists | home - top of the page - |
Linked lists
consists of structures (nodes) pointing to the next node.
In memory it is often described as looking like this:
---------- ----------
- Data - >- Data
-
---------- - ----------
- Pointer- - - - Pointer-
---------- ----------
struct node {
int x; node *next; }; int main() {
|
Here's what that looks like:
struct node {
int x; node *next; }; int main() {
|
conductor=root;
if(conductor!=NULL) { while(conductor->next!=NULL) { cout<<conductor->x; conductor=conductor->next; } cout<<conductor->x; } |
recursion | home - top of the page - |
Recursion
Recursion is defined as a function calling itself. Be careful. The
computer keeps function calls on a stack and once too many are called without
ending, the program will terminate. Try this:
#include <iostream.h>
void recurse(int count) { cout<<count; recurse(count+1); } int main() {
|
functions with variable nubmer of arguments | home - top of the page - |
Functions with variable-length argument lists
Some library functions can accept a variable list of arguments (such
as the venerable printf). You can write your own (for example to calculate
average of a variable number of numbers). You would use the stdarg.h
header file. Place an ellipsis (which looks like '...') in place of the
last argument. This will tell the compiler that the function should accept
variable number of paramenters.
There are four parts needed:
- va_list - datatype stores
the list of arguments.
- va_start - macro to initialize
the list, accepts 2 arguments: a va_list and the name of the variable that
directly precedes the ellipsis (...).
- va_arg - returns the next
argument in the list, accepts 2 args (a va_list and a variable type), and
returns the next argument in the list in the form of whatever variable
type it is told.
- va_end - cleans up the
variable argument list.
Example:
#include <stdarg.h>
#include <iostream.h> double average(int num, ...) { va_list arguments; // A place to store the list of arguments va_start(arguments, num); // Initializing arguments to store all values int sum=0; for(int x=0; x<num; x++) sum+=va_arg(arguments, double); va_end(arguments); //Cleans up the list return sum/(double)num; //Returns some number (typecast prevents trunctation) } int main() {
|
splitting program into separate files | home - top of the page - |
Splitting program into separate files: - put functions
declarations in a header file - and include it where necessary.
Then you can compile them together:
c++ f1.cpp f2.cpp
f3.cpp
myheader.h:
#include <iostream.h>
void f1();
|
f1.cpp:
#include <myheader.h>
void main() { cout << 1; f2(); }
|
f2.cpp:
#include <myheader.h>
void f2() { f1(); } |
f3.cpp:
#include <myheader.h>
void f3() { cout << 3; } |
static int f(); // static
means visible only in the current file.
extern void f(); // extern just
says that the function is described elsewhere. It is not really needed.
input / output:
cin, cout, cerr
cin.unsetf(ios::skipws);
// not to skip whitespace
cin.eof() - special function to
detect end of file
cin.bad() - checks success
char c = ' ';
while(1) { cin >> c; if (cin.eof()) break; if (cin.bad()) { cerr << "Input Error\n"; break; } cout << c; if (cout.bad()) { cerr << "Output Error\n"; break; } } |
misc | home - top of the page - |
// --------------------------
(*p).Height = 55;
strcpy(p->Name,"somename");
// --------------------------
setw(20) - sets width of the next output
#include <iostream.h>
#include <iomanip.h>
cout << setw(20) << "something" <<
setw(12) << "something else"
// --------------------------
&a[i] same
as &(a[i])
x[y] same
as *(x+y)
x[4] same
as 4[x]
// --------------------------
Person *p = A+2; // pointer initializing
(p-2) -> Name
&p[-2]->Name
p[-2].Name
(++p)->Name
// --------------------------
union {
Person P[500];
Mountain M[1000];
} U1;
// --------------------------
OOP - classes, constructors, destructor. | home - top of the page - |
OOP = Object Oriented Programming. Main idea - to make code modular and reusable. You keep methods close to the data they working on. You use inheritance to simplify development. While inheriting, you can override methods (polymorphism).
C++ = C +
one big addition (objects) +
bunch of small additions.
Classes = definitions (templates) of objects.
Class lists data structures (members) and functions (called
methods).
Objects are instances of classes.
Varialbes in classes can be public, protected or private.
Classes should always contain two functions: a constructor (named as
class) and a destructor (named ~class_name).
NEITHER constructors NOR destructors RETURN AN ARGUMENT!
Example of a class definition:
#include <iostream.h>
class Computer {
protected:
Computer::Computer() { //Constructors can accept arguments, but this
one does not
Computer::~Computer() { //Destructors do not accept arguments
void Computer::setspeed(int p) {
int Computer::readspeed() {
int main() {
|
Notes about constructors:
A class may have multiple constructors.
When you create an instance - the arguments of that
instance determine selection of the appropriate constructor (if there are
more than one constructor).
Default constructor - a constructor with no parameters
when all parameters have default values.
If the class doesn't have a constructor, C++ creates
a default one.
Copy constructor - one of parameters has the type
of the class
Array of instances - requires the use of the default
constructor
Destructor:
A class may have only one destructor - the name
is ~className
If you don't provide a destructor - C++ will create
a default one for you
Use destructor to free memory, close opened files,
and do other cleaning tasks
Note:
Same way you define class - you can also define a structure.
There are two differences:
= use the word "struct" instead of "class"
= by default:
the members of a structure
are public,
the members of a class
are private.
Note:
The keyword "this" may be used
in member functions. It is the pointer to an object which member function
is called.
Note: if you have constructor(s) with just one argument - you can initialize the class like this:
class mountain {
public: mountain(char *); //... }; mountain E = "Everest"; //
this will use the constructor with one parameter
|
friend, nested, static, namespace | home - top of the page - |
friend function
- a regular function, having an instance of a class as one of its parameters.
friend function has access to all members of the class (even the private
ones).
A function can be a friend of more than one class
A member functioin of one class can be a friend for another class
If you want to make all functions of one class to be friends of another
class - just make the whole class a friend:
class mountain {
friend class continent; // continent is a friend of mountain // ... }; class continent { .. };
|
Note:
If class A is a friend of class B, this doesn't mean that class
B is necessarily a friend of class A. But it can be.
Note:
there may be a member function and external friend function
with the same name. There is no confusion, because their fully qualified
names (with namespace prepended) are different.
Nested Data Types:
C++ allows to declare enumerated types, structures, and classes
inside other classes. Their fully qualified name starts with the name of
the external (host) class, for example: Window::Rectangle.
static members (data and functions):
static - belongs to a class - not to an instance.
static data - there
is only one copy of this data, regardless of how many objects of this class
are created. It may be used for counting class instances, shared information,
iterators, shared error status, instance communication, etc.
Note: (important): The declaration of the static member
in a class does NOT define it. You have to define/initialize a static member
outside the class. For example:
class Account {
public: // ... private: static int deposits; }; // defining and initializing of the static variable.
|
static member functions: - is used to access nonpublic static data members (which are usually made protected) and other static functions. It can not use the pointer "this", because it doesn't depend on a specific object.
namespace feature
You can define names for classes, variables, types in different namespaces.
If NN is the name of a namepsace,
and cc - name of the variable defined
in this namespace, then
NN::cc
is a fully qualified name for this variable.
The default global namespace is an empty string, so you can write:
::cc
or simply cc
The standard library is defined in the namespace std
Operator overloading | home - top of the page - |
Operators:
You can declare operators in a class - essentially member functions
that have special declaration and usage syntax.
For example:
operator+ ( )
operator- ( )
etc.
Here is an example of declaration:
#include <iostream.h>
class number {
number operator+ (number N1, number N2) {
number operator+ (int N1, number N2) {
void main( ) {
Z = operator+(X,Y); // explicit call to operator+( ) function
Z = operator+(1,Y); // explicit call to operator+( ) function
Output:
|
Using friend operator function (to access private nenbers):
#include <iostream.h>
class number {
number T; // temporary global object number& operator+ (number&
N1, number& N2) {
ostream& operator<< (ostream&
Cout, number& N) {
void main ( ) {
|
abstract class, parent-child hierarchy | home - top of the page - |
abstract classes
class is abstract if it has at least one pure virtual function
(function is made "pure" by using initializer "=0"), for example:
class Shape {
public: virtual void draw( ) = 0; // pure virtual function // more definitions } |
class hierarchy (inheritance)
Here is how to declare a descendant class ( MyChildClass ) from
a parent class ( MyParentClass ):
class MyChildClass : public MyParentClass {
public: // constructors, destructor, members, member functions protected: // constructors, destructor, members, member functions private: // constructors, destructor, members, member functions } |
children inherit data and function members from parent(s)
multiple inheritance
it is possible to have several parents, for example:
class MyChildClass : MyParentClass1, MyParentClass2 {
// ... } |
The parents in the list may have prefixes like "virtual" or/and "public",
for example:
Class MyObject {..}
class Salary : virtual public MyObject { ... } class Person : virtual public MyObject { ... } class Employee : virtual public Person, virtual public Salary { ....} |
Note:
"virtual" tells the compiler that parents share common ancestors
"public" tells the compiler that class instances can access
the public members (of the parent). Without this word, the inheritance will be by default private, so only the member
functions of children can access the public members of the parent class.
private,protected, public (inheritance and encapsulation) | home - top of the page - |
access modifiers: public, protected, private
- private is a default for members of a class
- public is a default for members of a struct
- the access level does not apply when defining the member outside
of its class (this is used when defining the static members)
members:
public member:
can be accessed from anywhere, including from outside the class protected member:
private member:
|
classes:
class MyAccount: public Account;
public inheritance:
This is an "is a" relationship between derived classes and the base class - public members in the base class remain public in the derived classes. - protected members in the base class remain protected in the derived classes protected inheritance:
private inheritance:
|
virtual functions | home - top of the page - |
Imagine that we create a generic class (Parent) with functions which will be overriden in children. Imagine that we have an array of pointers of the Parent type, and we point these pointers to objects of different derived classes. Imagine that we want to call certain method on all these objects. And instead of simply calling the same generic method from the Parent, - we want the compiler to do some extra work and trace to call different overriding methods from child classes. So that the method should correspond to the object. To achieve that we should add the word "virtual" in front of the function declaration.
So the word "virtual function" means that the function declaration serves like an interface. It can be overriden (re-defined) in the derived classes. If the function is virtual, than the compiler and loader will call the correct function for an object.
- virtual function can override a virtual or nonvirtual member function
that is inherited from a parent class
- "once virtual - always virtual" - a virtual parent in parent can
not be overriden in children by a nonvirtual function.
- you may overload a virtual function with a nonvirtual function. However
the children can inherit only the virtual function.
Here is an example showing the difference in virtual / non-virtual
behaviors:
#include <iostream.h>
class P { // Parent
class C : public P { // Child class derived from Parent
main() {
// non-virtual
// virtual
output:
|
Virtual function allow for polymorphism, one of the great buzz
words in Object Oriented programming. What this means is that objects of different
derived classes can respond to the exact same message in different ways. In
the example above, a child class "C" is derived from a parent class "P". A pointer
"pp" of the parent type is pointed to an object "c" of the child type. Now if
this pointer is used to call a function which is defined in the parent and overriden
in the child, then the question is: which function will be used:
- the one defined in parent (as the pointer is of the
parent type)
- or the one defined in the child (because the object
is of the child type).
Please note the diffference when this pointer is used to call a virtual
or non-virtual functions. Note that for virtual function the method
of the child is called. Which is probably what you want. Thus with
a virtual function, the class of the object pointed to determines
the function definition to be used.
Exceptions | home - top of the page - |
Exception classes:
Skeleton classes - no members
Classes with data members
Standard Exceptions:
Exception Class | Parent Class | Purpose |
exception | None | The base class for all of the exceptions thrown by the C++ standard library |
logic_error | Exception | Reports logical program errors that can detected before the program proceeds to execute subsequent statements |
runtime_error | Exception | Reports runtime errors that are detected when the program executes certain statements |
ios::failure | Exception | Reports stream I/O errors |
domain_error | logic_error | Reports infraction of a condition |
invalid_argument | logic_error | Signals that the argument of a function is not valid |
length_error | logic error | Signals that an operation attempts to create an object with a length that exceeds or is equal to NPOS (the largest value of the type size size_t) |
out_of_range | logic_error | Signals that an argument is out of range |
bad_cast | logic_error | Report an invalid dynamic cast expression during runtime identification |
bad_typeid | logic_error | Reports a null pointer in a type identifying expression |
range_error | runtime_error | Signals invalid postcondition |
overflow_error | runtime_error | Signals arithmetic overflow |
bad_alloc | runtime_error | Signals the failure of dynamic allocation |
Throwing an exception:
throw exceptionObject;
try {
// throw myError
}
catch(int myError) {
// process error here
}
templates | home - top of the page - |
Often you need to have a class to do the same operation - but with different data types. Then you can define a template one time - and then use it in the code with different types:
Example: let's create a template to hold 3 objects - and calculate their sum( ).
template <typename T>
class coolHolder { public: T i,j,k; T sum( ) { return i + j + k; } }; |
Now here is how we can use this template with different types (int , float):
void main( ) {
coolHolder<int> IntHolder;
coolHolder<int> AnotherIntHolder;
coolHolder<float> FloatHolder;
} |
The code of functions in template can be declared inside the template class declaration, but detailed later outside the class declaration, for example:
template <typename T>
class myclass { protected: T x; public: T& getx( ); // function returns a reference. This allows to avoid unnecessary copying. void setx(T); }; template <typename T>
template <typename T>
void main( )
|
Note: If you include a static member in a template - then each class that you create using this template will get its own static member. As usually with static data members, you have to define the storage (initialize the variable) outside of the class declaration. Example:
#include <iostream.h>
#include <stdlib.h> // first, class declaration template
// second, static variable definition template
// now we can define and use it
cout<< myClass<int>::mystatvar <<endl;
output:
|
p.487: parameterizing a template
...
programming with STL | home - top of the page - |
p.508