C++ was invented in 1979. after that, it underwent three major revisions: in 1985 then in 1990 and in 1994 during the C++ standardization process.
The 1994 C++ standard was proposed by a joint ANSI and ISO committee. That draft largely reflected the state of C++ at that time.
Soon after the the first draft, STL was created. STL is considered to be both powerful and elegant, but large.
By 1998, C++ standard, including STL, has been mostly completed.
There are really two versions of C++: the oringal by Bjarne Stroustrup's design, and the new standard C++, created by Stroustrup and ANSI/ISO committee Important differences exist between the two, for instance, the new style headers and the namespace statement.
#inlucde < iostream > using namespace std; int main () { return 0; }
Note: C's stdio.h is C++'s iostream.h. In C++, standard C headers are still included, simply add a "c" prefix and drop the .h, i.e:
#include < math.h > --> #include < cmath > #inlucde < string.h > --> #include < cstring >
but, this approach is deprecated. you should try to use the new style headers, whenever possible.
A namespace is a declarative region, with its purpose to localize the names of identifiers to avoid name collisions. The contents of the new-style headers are placed in the std namespace.
using namespace std; // puts std into the global namespace class myclass { // private functions and variables int a; public: // public functions and variables void set_a(int num); int get_a(); } object-list; //object-list is optional void myclass :: set_a (int num) { } myclass ob1, ob2; ob1.set_a(10); ob2.set_a(99);
Note: in C,
char f1(); /* means nothings is said about the parameters*/ char f1(void); /*means f1 takes no parameters*/
But in C++, the above two are the same! -- meaning f1 takes no parameters
In C, function prototypes are recommended but technically optional. In C++, prototypes are required!
in C, a function with non-void return value actually is not required to return a value (in that case, a garbage value is "returned"). In C++, you are required to return something, unless you declared void return type. Also, in C++ the default-to-int-return assumption has been dropped.
Unlike in C, C++ defines the bool data type, with can only evalute to two values true and false. (bool, true, false are reserved words).
void f1 (int a); void f1 (int a, int b);
are different.
class myclass { // private functions and variables int a; public: // public functions and variables myclass(); ~myclass(); void set_a(int num); int get_a(); } object-list; //object-list is optional myclass:: myclass() { } myclass:: ~myclass() //destructor takes no input { }
It is common to overload a class's constructor function, for 3 main reasons: 1. to gain flexibiity
class myclass { int x; public: myclass() {x = 0;} myclass(int n) {x = n;} };
2. to support arrays, you would need myclass() to declare,
myclass ob[20]; or, myclass * myp; myp = new myclass [20];
3. to create copy constructor
- the default is a bitwise copy, usually not desirable to do that - needed when an object is used to initialize another in a declaration statement - needed when an object is passed as a parameter to a function, and - needed when a temporary object is created for use as a return value by a function
The most common form of copy constructor is:
myclass (const myclass &obj) { // body of constructor }
Note: copy constructor only applies to initializations (i.e. the above 3 scenarios), BUT NOT to assignments.
myclass x = y; // copy constructor func1(y); // copy constructor called implicitly y = func2(); // copy constructor called implicitly x = y; // no call to copy constructor. if no "=" overloading, then bitwise copy
One object may be assigned to another provided that both objects are of the same type. By default, a bitwise copy of all the -data- memebers is made, including compound data such as arrays.
Objects passed to functions as parameters are all passed by value. i.e. a bitwise copy of the argument is made. note, in this case, when the function is called, a constructor is called, and when the function returns, the destructor is called.
A function can return an object as well. the process is the following: a temporary object is created (calling constructor) and after the object is returned, this object is destroyed (calling destructor).
This kind of assignment is using the default copy constructor, however. the proper way to do so, is to define a correct copy constructor.
A function that have access to the private members of a class, without actually being a member of that class, useful for
- operator overloading - creation of certain types of I/O functions - for a function to access the private members of two or more different classes
class myclass { int d; public: myclass (int i); friend int isfactor (myclass ob); }; int isfactor (myclass ob) { if (ob.d ... } int main() { myclass ob1; if (isfactor(ob1)) ... }
Note, unless you have great reasons, avoid using friend functions. The following features are always helpful to remember though.
1. friends are called just like regular functions. 2. friends can only access private data members in conjunction with an object that's declared within or passed to the friend function 3. a friend function is not inherited. i.e. when a base class includes a friend function, that friend is not a friend of a derived class 4. a friend func can be friends with more than one class 5. a function can be a member of one class and a friend of another
Base class access control comes in three types: public, protected, private
class derived-class-name: access base-class-name { }
As in:
class B { int i; public: B(); }; class D: public B { int j; public: D(); };
If not access control is specified,
- it is private by default if the derived is a class - it is public by default if the derived is a struct
Note:
- if you want everything remain the same access categories, do public inheritance - if you want everything from base to be private, do private inheritance - in the derived class, members from the base class become:
public inheri protected inheri private inheri public members public protected private protected members protected protected private private members private private private
In the derived class, members from the base class is accessible by the derived class:
public inheri protected inheri private inheri public members Yes Yes Yes protected members Yes Yes Yes private members No No No
class base { int x; public: void setx(int x); }; class derived : public base { int y; public: void sety(int y); }; derived ob; ob.setx(5); // fine ob.sety(10); // fine
class base { int x; public: void setx(int x); }; class derived : private base { int y; public: void sety(int y); }; derived ob; ob.setx(5); // illegal ob.sety(10); // fine
With inheritance: the constructor functions are executed in order of derivation (base first, derived second), while the destructor functions are called in the reverse order.
Passing parameters to the constructors is a bit tricky, a chain of argument passing is established. Everything is first passed to the derived class's constructor using an expanded form of the derived class's construction declaration, parameters are then passed along to the base class
class base { int i; public: base(int n) {i = n; } }; class derived: public base { int j; public: derived(int n, int m): base(m) { cout<<"constructing derived class\n"; j = n; } };
note: the derived class's constructor does not have to use any of those parameters passed in, but it needs to pass them on as needed.
- indirectly inherit through a base class, i.e. A --> B --> C, in a multi-level fashion - directly inherit from multiple base classes (our focus here)
class derived-class: access B1, access B2, access B3 ... { }; derived-class:: constructor(arg-list): B1(argl), B2(arg2), B3(arg3) ... { }
Note: constructors of base classes are called in left-to-right order and then the constructor of the derived class, and destructors are executed in the reverse order. With multiple inheritance, there is a possibility that one base class could be inherited multiple times, kind of in a dimond setup. Then, there is an ambiguity in that the base could be included twice in the final derived class.
In C++, the keyword virtual makes sure that ALWAYS only one copy of the base class in included in the final derived class.
class base { }; class D1: virtual public base { }; class D2: virtual public base { }; class fD: public D1, public D2 { };
A pointer declared as a pointer to a base class can also be used to point to any class derived from that base. You can only use the pointer to access those members that were inherited from the base. Pointer arithmetic is relative to the data type the pointer is declared. So:
base * p; deri x[2]; p = x; p++; // will not point to x[1]
Given the above is the case, the base class must have all functions to be called even with the derived class. Otherwise the base pointer is useless. virtual function is used for this purpose, declared within a base and redefined by derived classes. Actually, virtual function is the ONLY good way to get runtime binding. To get it, just precede the function's declaration with the keyword virtual.
When redefining a virtual function in a derived class, the keyword virtual is not needed. NOTE: to design for inheritance, if you want the correct version of a member function to be called, you need to make that function virtual! Also, it's a very good idea to make the destructor virtual, otherwise delete won't call the right one (i.e. base or derived?).
class base { public: int i; virtual void func() { cout<<"do something\n"; } }; class derived : public base { public: derived1(int x): base(x) {} void func() { cout<<"do something different\n"; } }; base * p; derived ob1; p = &ob1; p->func();
output:
do something different
Note: If derived does not redefine/override func, still the func in base class is called
Pure virtual functions achieve two goals:
1. the base class is simply for interface purpose 2. the derived class must override this function (you cannot assume any implementation in the base class. thus, avoiding possibility of an overlooked error)
Just do:
virtual type func-name(parameter-list) = 0; class area { double dim1, dim2; public: void setarea(double d1, double d2); virtual double getarea() = 0; }; class rectangele: public area { public: double getarea() { return d1*d2; } };
template < class Ttype > ret-type func-name(parameter-list) { // body of function }
The word "class" here only means to specify a generic type. it can be replaced by "typename", i.e.
template < typename Ttyep > ret-type func-name (parameter-list); // is also fine
i.e.
template < class X > void swapargs (X &a, X &b) { X temp; temp = a; a = b; b = temp; } int main() { int i, j; float x, y; swapargs(i, j); // this works swapargs(x, y); // this also work swapargs(i, y); // this does not work ... }
It is the compiler's job to create two versions of swapargs, one for int and one for float, at compile time. The following is also fine:
templatevoid swapargs (X &a, X &b) { X temp; temp = a; a = b; b = temp; }
Note: no other statements can occur between the template statement and the start of the generic function. You can define more than one type in a template statement, just use a comma-separated list:
templatevoid out1(X x, Y y) { cout << x << " " << y << end; } out1(10, "hi"); out2(0.23, 10L);
you can overload a generic function. note, you really overload just one instance of the generic function each time, and the overloaded version will take precedance
void swapargs(int a, int b) { cout<<"just to be different\n"; } float x, y; int i, j; swapargs(i, j); // outputs "just to be different" swapargs(x, y); // swaps x, y
Generic classes, very useful when class contains generalizable logic, i.e. maintaining a queue of int, float, etc.
template < class Ttype > class class-name { }; class-name < type > ob; // defines a specific instance ob
Member functions of a generic class are themselves automatically generic. No need to define each one explicitly using keyword template. C++ provides a library built upon temalte classes, referred to as STL.
tempalte < class dT > class list { dT data; list *next; public: list(dT d); void add(list *node) {node->next = this; next = 0; } list *getnext() { return next; } dT getdata() { return data; } }; template < class dT > list< dT > :: list(dT d) { data = d; next = 0; } int main() { list < char > L1('a'); list < char > *p, * last; last = &L1; for (int i = 0; i < 26; i ++) { p = new list < char > ('a'+i); p -> add(last); last = p; } }
In a way, you can treat list< char > as the name of the class we are referring to in this example.
list < int > int_headnode(1); // this creates the head node of the linked list
or,
struct addr { char name[40]; char street[40]; char city[40]; char state[3]; char zip[12]; } addr structvar; listaddress_head(structvar); // this is also fine
Like generic functions, generic class can also have more than one generic data type. simply declare all the data types required in a comma-separated list withint the template specificication
templateclass myclass { T1 i; T2 j; public: myclass(T1 a, T2 b) { i = a; j = b; } } myclass ob1(10, 0.23);
For the most part, C++ is a superset of ANSI C, however a few differences do exist:
1. in C a character is automatically elevated to int, not in C++ 2. in C declaring a global variable several times is okay (a bad form though), not in C++ 3. in C an identifier has at least 31 significant characters. in C++ all characters are significant 4. in C, you can call main() recursively, not in C++ 5. in C you cannot take the address of a register variable. in C++ you can 6. in C the type wchar_t is defined with typedef. In C++ wchar_t is a keyword 7. in C++, a function definition can explicitly take 0 to say that input argument is ignored. not in C. int except_handler(0) { }