; AUTHOR: GPL(C) Mohsin Ahmed, http://www.cs.albany.edu/~mosh vim:ft=c: moshtag=c++,class access_specifier: public | private static data, static functions, non static functions, non static data eg. class CLX { char* pstr; // default is private. public: CLX(); // default constructor CLX(char* pc); // decl for each argument signature. CLX(const CLX &c); // copy CTOR virtual ~CLX(); // destructor // other member data and functions. }; CLX::CLX(){ } // ctor defn. CLX::~CLX(){ } // dtor defn. CLX c; // instantiation. void main(){} // so that we can compile with vc5 or g++. moshtag=Constructors,CONS,CTOR: - Cannot be static, nor virtual - nor return anything (not even void). - Cannot be called. - eg. CLX::CLX(){ pstr = 0; } - Used for any new object without args, or with new. No need for parenthesis in this case. - new array of objects. - insufficient initializers - eg. CLX::CLX(char*pc){ pstr = pc; } COPY CTOR - obj C1 initialized from another C2. eg. C1 = C2; - arg to a function. eg. f(C1); - return obj from a function, eg. f(CLX c){ CLX d; ...; return d; } - eg. CLX::CLX(const CLX c){ pstr = new char[strlen(c.pstr)]; strcpy(pstr,c.pstr); } moshtag=Destructors,DTOR: - NO (never has any) arguments. - Cannot be static, const, nor volatile. - Can (Should be) be virtual. - eg. CLX::~CLX( ){ delete [] pstr; } - Only one DTOR per class, implicitly called when obj goes out of scope, before object is destroyed (freed/deleted). - Donot confuse with 'delete' operator, which frees the mem. - eg. CLX::~CLX(){ delete [] pstr; } // delete takes care of NULL pstr. Conversion: Converts a DataType to class CLX. CLX <----> DataType <- CLX( DataType ); // conversion ctor. -> operator CLX::DataType(); // conversion operator. Auto Conversions: - Compiler will auto convert, but not thru user defined promotions. FRAC f1 = 21; // compiler might use FRAC::FRAC(int i) to cons f1. - Stop auto conversions by declaring them to be private, dummies defn. Static data/functions: - Exists independent of any object instance. - Static data must be defined/initialized outside the header file. eg. class CLX { public: static int count; static int GetC(); }; int CLX::count = 1; // defined and initialised outside. int CLX::GetC(){ return count; } #include void main(){ CLX c1,c2; cout << CLX::count // Accessing the static members. << CLX::GetC() // cleaner << c1.GetC() // GetC() unrelated to instance c1. << c1.count << c2.count; } moshtag=friend Friend function frt() of class CLX is - Not part of CLX, but frt() may access private data of CLX. - Needs the class as a arg. - Used to allow commutative and associative operations. - eg. class CLX { int n; } friend CLX operator-(const CLX c, const CLX d){ return CLX(c.n-d.n); } Operator functions: - operator@ is the name of the function. - eg. class CLX { int n; CLX operator+(const CLX c){ return CLX(n+c.n); } } Default Functions: These are generated by the compiler if required and not defined. CLX(); // default ctor, CLX::CLX(){ ;} - no action ~CLX(); // default dtor, ~CLX::CLX(){ ;} - no action CLX( const CLX& ); // copy ctor, .. - mem-copy. CLX& operator= (const CLX&); // Assignment operator. const CLX* operator& ()const; // addressof, return const this; CLX* operator& (); // addressof, return non const this; Copy CTOR vs ASSignment Operator: CLX c(d1); // cons c and copy d1 into c. VS delete c; c = d2; // assignment operator: used for an existing LHS. eg. #include class CLX { char* pstr; CLX& CLX::operator= (const CLX& d){ if( this != &d ){ // special case: c = c; is NOP. delete [] pstr; pstr = new char[strlen(d.pstr)]; strcpy(pstr,d.pstr); } return *this; } }; void main(){ } moshtag=this THIS 'this': - Available only in member functions, pointing to the object invoking the member function. - Not available to friend/static/global functions. - CLX* is typeof(this), and CLX is typeof(*this). - eg. class CLX { int n; CLX operator++(); } CLX CLX::operator++ () { n++; return *this; } moshtag=member POINTER to MEMBERS - generic offets, not specific to any object instance. - Operators: .* deref a member of a object (via a object, eg above). ->* deref a member of a object (via a pointer to instance). - eg. class CLX { public: int n; int k; }; void main(){ int CLX:: *pn; // offset to any int in class CLX. pn = &CLX::n; CLX c1; (c1 .* pn )++; // same as c1.n++, paren required. CLX c2; (c2 .* pn )++; // same as c2.n++ CLX*d1 = new(CLX); (d1 ->* pn )++; // same as d1->n++ pn = &CLX::k; (c1 .* pn )++; // same as c1.k++ (d1 ->* pn )++; // same as d1->k++ } - eg. #include class CLX { public: int if1(){ return 1; }; int if2(){ return 2; }; }; void main(){ int (CLX:: *pfi)(); // offset to any function of CLX returning int. pfi = CLX::if1; // not a call to if1. CLX c1; cout << (c1 .* pfi)(); // call c1.if1, via offset pfi. CLX*d1 = new(CLX); cout << (d1 ->* pfi)(); // call d1->if1, via offset pfi. } Static functions: eg. new and delete operators, exists before any instance of the class. const functions: - Keyword 'const' appears after args, ie. func(arguments) const; func(arguments) const { defn }; - Cannot change any data, but see seemingly const (eg. read, with disk caching). - Only these functions can process const object, ie. const obj can be args only to these functions. - non const objects can be process by all member functions. Nesting-vs-inheritance: Nesting classes: has-a class CLX { class HSX; } // class CLX has-a HSX. Inheriting: is-a class HSX : public CLX { } // class HSX is-a CLX also. Classes-vs-Structs-vs-Unions: - Struct are classes with default access as public. o also base classes public by default. - Classes are struct with default access as private. o default member functions generated automatically. - Unions, access like structs. o Cannot be a base class, nor have virtual functions, not static data. ======================================================================= mosh_tag=Inheritance eg. class DLX : public B1, public B2 { .... }; - DLX can access public and 'protected' members of base class. - DLX can make access of Base's member more restrictive, but not more accessible. - eg. class DLX : private RLX { ... }; Now RLX is accessible only inside of DLX. - Derived class contains everything in its base, it can refer to its members and all non-private members of it's base classes. - DLX can 'overrride' inherited members with its own definitions, it can deactivate inherited members by making them private. - 'indirect-base' is a base class up a chain of inheritance. Virtual inheritance: To prevent multiple copies of base classes appearing in derived, maybe thru a chain of inheritances. eg. class DLX : virtual public B1 { .... }; Ctors: - No inherited, default generated when required. Drived ctor calls base ctor first. - eg. class DLX : public B1, B2 { ... }; DLX d; // base B1, B2 ctor (in same sequence) called before DLX ctor. Dtors: - No inherited, default generated when required. base dtor invoked in reverse order. - non virtual dtor, only base's dtor called. - virtual dtor also calls base dtor, ie after executing derived dtor code. Scoping '::' - Call explicity a base class' member function, eg. class DLX : public B1{ ... B1::f() ... }; See examples in separate files (to be decided). ======================================================================= Operators: - Three forms: Members, Friends, Global. - Non-overloadable: '.' member selection '.*' member selection via pointer. '::' scope '?:' conditional sizeof size of - Cannot define/declare new operators. - Cannot change inbuilt types, eg. int. - Cannot change o precedence, nor o associativity, nor o signature (#args). - Different signature means treated separately. eg. Unary minus, and binary minus. - Associavity/communtativity is semantic, not syntactic. - Same signature operator, cannot be both member and friend - choose one. - Calling an operator@() o explicity: c1.operator@( args ); // unary, or c1.operator@( c2 ); // binary, or operator@( c1, c2 ); // global friend. o implicitly: c1@, or @c1, or c1 @ c2; unary operator: eg. class CLX { public: int n; CLX operator- (void){ return CLX(-n); } CLX operator+ (CLX v){ return CLX(n+v.n); } CLX operator- (CLX v){ return CLX(n-v.n); } // friend CLX operator- (CLX u,CLX v); CLX(void ) : n(0) { ; } // default ctor. CLX(int i) : n(i) { ; } // ctor. }; // unary- can't be a global and binary- a member function. // CLX operator- (CLX u,CLX v){ return CLX(u.n-v.n); } // global friend. void main(){ CLX c(5),d; c+d; -c; // implicit calls. c-d; c.operator-(); // explicity call. c.operator+(d); c.operator-(d); d.operator-(c); } Prefix-vs-postfix: - Postfix is a binary operator, with default arg of zero. eg. ++c, c++, --c, c--; ++c; c.operator++( ); // explicity call to prefix. c++; c.operator++(5); // explicity call to postfix. // c++5 -- invalid syntax. operator Conversion(): - Convert from class to a datatype, syntax: operator datatype(). eg. class CLX { int n; public: operator float(); // CLX to float. operator int(); // CLX to int. CLX(int i): n(i){;} // ctor }; CLX::operator float(){ return (float) n; } // trivial example. #include void main(){ CLX c1(21); // float f1 = c1.float(); // illegal usage. float f1 = float(c1); // usage. float f2 = c1; float f3( c1 ); cout << (float) c1; } operator[] Const: - Returns a ref to a unmodifiable (const) array, - TYPE& CLX::operator[] (ARGS) const; // syntax. eg. class CLA { int n; int* pa; CLA(int s){ pa = new int[n=s]; }; ~CLA(){ delete pa; n = 0; } const int& operator[] (int i) const { return pa[i]; } } operator()(): - Doubt of usage? - TYPE CLX::operator() (ARGS); // syntax. operators <<,>> IO: - Syntax ostream& operator<< (ostream& os, CLX& c); istream& operator>> (istream& is, CLX& c); - Make them a friend, to access private data of CLX. Eg. #include class CLX { public: int n; CLX(int i) : n(i) { ; } friend ostream& operator<< ( ostream& os, CLX& c ); }; ostream& operator<< (ostream& os, CLX& c ){ os << c.n; // or, return os << n; return os; // Return ref to ostream, can we can chain calls. } void main(){ CLX c1(5),c2(9); cout << c1 << c2; ( cout << c1 ) << c2; // same operator<< ( operator<< ( cout, c1 ), c2 ); // same. } operator -> (): - Unary, returns a pointer to the instance, - used for smart pointers. eg. class CLA { int* cache; CLA* operator -> (); }; #include CLA* CLA::operator -> () { assert( cache ); return this; } void main(){} operator new(), delete(): - Should not cause any recursion (back to new() or delete() ). - Global new() and delete(), always static. - global new() always used for arrays. - delete[] - used to delete arrays, older c++ was: delete[length]. - member new() and delete(). Syntax: void* operator new (size_t length [,PlacementArgs] ); void* operator new[] (size_t length [,PlacementArgs] ); void operator delete (void* ptr [,size_t obsize] ); void operator delete[] (void* ptr [,size_t obsize] ); Here ptr is pointer to object, optional obsize. ======================================================================= moshtag=virtual Virtual Functions: Runtime Polymorphism. As opposed to compile time binding (where the compiler plugs in a fixed address of a function to call). Here the compiler doesn't know what obj ptr will point to at compile time. Compiler cannot generate 'call _f'. The obj ptr may point to the original virtual function, or to the derived overriden function. Instead the pointer to virtual function is kept in the object, and call is indirect thru a vtable. - Invoked only thru pointer to object. - 'virtual' keyword in base decl. - Must have same signature, else treated as different unrelated funcs. eg. class BLX { public: virtual int f(){ return 31; } // virtual int f(int i){ return 71; } // non-virtual }; class CLX : public BLX { public: int f(){ return 21; } // also virtual because of above. int f(int i){ return 91; } // static }; #include void main(){ CLX c1; BLX b1, *d1 = &c1; cout << c1.f() // '21' always statically bound, ie. 'callsub _f' << c1.f(1) // '91' << d1->f() // '21' called via vtable 'callsub vtable[_f]' << d1->f(1) // '71' called statically in BLX, even when pointing // to a CLX object. << b1.f() // '31' << b1.f(1) // '71' ; d1 = &b1; cout << d1->f() // '31' f dynamically looked up. << d1->f(1) // '71' statically calling BLX::f(int). ; } ======================================================================= moshtag=Templates - Types as arguments - Instantiated only when required. - arguments are generic classes GC. Syntax: template < GC > usual class or function defn using GC; eg. Below a>b is a.operator>(T b), not the numeric comparator. template T max( T a, T b){ return a>b? a: b; } #include void main(){ cout << max(1.414,3.141) << ',' << max(21,31); } ======================================================================= moshtag=stl,template STL/Standard Template Library: containers: array, list, hash iterators: like pointers to elements in containers. stl/vector: eg [ #include using namespace std; typedef vector VN; typedef VN::iterator VNI; #include void main(){ VN c1(10); // members of c1 // VNI begin(), end(), [don't forget the parenthesis!] // int size(), max_size(), capacity(); // bool empty(); // N& operator[]( int ), front(), back() // void push_back(N&), pop_back(), clear(); // VNI insert( VNI, N ), erase(VNI) // Resizing insert/deleting inbetween invalidates all iterators. for(int i=0; i<10; i++ ) c1[i] = i; for(VNI v1 = c1.begin(); v1 != c1.end(); v1++ ) cout << *v1 << ' '; } ] stl/list: eg #include void main(){ std::list L; } eg [ #include #include using namespace std; typedef list LN; typedef LN::iterator LI; void main(){ LN c1; // c1 is a list of ints // members of c1: // bool empty(); // LN begin(), end(); // push_back(N), push_front(N), insert(LI, N); // void pop_front(), pop_back(), clear(), remove(N&), unique(); // reverse(),sort(); // LI erase(LI), erase(LI,LI); // N& front(), back(); // splice(...) // see stl/List.html for more members LI a1 = c1.begin(); // a1 can point to an element in c1. c1.push_back(51); c1.push_front(71); c1.insert( a1++, 21 ); for( a1 = c1.begin(); a1 != c1.end(); a1++ ) cout << *a1 << ','; // 71,51,21, } ] =========================================================================== stl/map: eg [ #include #include #include // typedef std::map MT; // typedef std::map::iterator MI; using namespace std; // instead of prefix std above typedef map MT; typedef map::iterator MI; void main(){ MT m1; // m1 has member functions: // int max_size(), size(); // bool empty(); // MI begin(), end(),find(string); // erase(MI,MI); m1["hello world"] = 10; // map m1: string -> integer. m1["bye bye"] = 31; for( MI mi = m1.begin(); mi != m1.end(); mi++ ){ cout << (*mi).first << '=' << mi->second << endl; } cout << m1.find("bye bye")->second; } ] stl/algorithm: eg [ #include #include #include using namespace std; void doit(int n){ cout << n << ' '; } void main() { typedef vector VN; typedef VN::iterator VNI; VN n1(8); for (int i=0; i < 8; i++) n1[i] = i; for(VNI it = n1.begin(); it != n1.end(); it++) cout << *it; for_each(n1.begin(), n1.end(), &doit ) ; } ] String list: eg [ #include #include #include using namespace std; void main() { list strlst; strlst.push_back(string("Try")); strlst.push_back(string("Mosh")); strlst.push_back(string("Try")); strlst.push_back(string("Mosh")); strlst.remove( string("Try")); while (strlst.size()) { // prints: Mosh\n Mosh\n cout << strlst.front() << endl; strlst.pop_front(); } } ] ======================================================================= EOF