- OOP encapsulates data(attributes) and functions(behaviors) into packages called classes.
- A class is a user-defined data type that acts as a blueprint for instantiating any number of objects of that class.
- Classes have property of information hiding i.e. a class know how to communicate with another class across well-defined interface, however, they are not allowed to know how they are implemented i.e. implementation is hidden.
- C & other procedural languages are action-oriented. In C, unit of programming is function. Verbs in system specifications help in determining required set of functions.
- C++ is object-oriented language. Unit of programming is classes from which objects are eventually instantiated. Nouns in system specifications help in identifying required classes.
- C++ classes are natural evolution of C struct which is a collection of related variables whereas a class contains both variables (data members) and functions (member functions) that manipulate those data.
- Member functions are also called operations or methods. Methods are invoked in response to messages sent to an object. A message corresponds to a member function call sent from one object to another or sent from a function to an object.
- General syntax of a class is
access-specifier 1: ---------------- can be public, private or protected
className( ); //constructor
member function prototypes;
data member declarations;
};--------------Forgetting this is a syntax error
- Member Access Specifiers
- Public Accessible where the program has access to an object of that class
- Private Accessible only to member functions and to friends of that class
Data members are usually private and member functions are public. However, this is not a hard and fast rule.
Public member functions are also called interface of the class.
- A member function with the same name as the class.
- It initializes the data members of a class object.
- Called automatically when an object of that class is created.
- There can be many constructors accomplished through function overloading.
- Specifying a return type or a return value for a constructor is a syntax error.
- Default Constructor is a constructor with no parameters
- The default constructor takes no parameters, whether you declare it or get it free from the compiler
- If you declare any constructor, the compiler will not provide a default constructor
- Once the class has been defined, it can be used as a type in object, array, pointer or a reference.
- Data members may be private as they may be of no concern to class' clients. Thus, implementation is hidden and this information hiding promotes program modifiability and simplifies the clients' perception of a class.
- Member functions are usually shorter than non-object oriented programs because the data stored in data members have ideally been validated by a constructor and/or by member functions that store new data. Because the data are already in the object, the member function calls often have no arguments or atleast few arguments than typical function calls in non object oriented languages. Thus, the calls are shorter, function definitions are shorter and function prototypes are shorter.
- Attempting to initialize a data member of a class explicitly in a class definition is a syntax error.
- A member function the same name as the class and with prefix ~ i.e. ~className( );
- If no destructor is specified then the system 'plugs-in' one destructor.
- The destructor does 'termination housekeeping' on each class object before the memory for the object is reclaimed by the system.
- Destructors cannot take arguments and hence, cannot be overloaded.
- Destructors have no return value.
- Declaring member functions inside a class definition (via their function prototypes) & defining those member functions outside the class definition separates the interface from of a class from its implementation. This promotes good Software Engineering as it hides implementation from class' clients and also class' need not recompile if implementation changes; provided interface remains same. Member functions declared outside in a class definition can be defined outside class definition using binary scope resolution operator ::. If member function is defined outside then use of class name and :: is mandatory as it ties function to a class and two classes may have functions with same name. However, scope of such functions is that of class only.
- Member functions defined in class definition are automatically inlined whereas those defined outside can be inlined using inline keyword. However, compiler reserves the right whether to inline a function or not.
- From performance point of view, smaller functions can be defined in class definition for making inline but it is not good from Software Engineering point of view because it exposes code to class' clients and also clients need to recompile if inline function changes.
- Only simplest and most stable member functions should be defined in class header. Member function calls generally take either no arguments or substantially fewer arguments than conventional function calls. This reduces likelihood of passing wrong arguments. Number of arguments are reduced because of encapsulation of data members and member functions within an object gives the member functions within an object gives member functions the right to access the data members.
- Member functions are usually designed to be client-oriented rather than implementation oriented. OOPs imply re-use i.e. crafting valuable classes & creating valuable "software assests". Often classes need not be created from scratch. They may be derived from other classes that provide attributes and behaviors the new classes can use (inheritance) OR classes can include objects of other classes as members (aggregation or composition). Such software re-use can greatly enhance programmer's productivity.
Class Scope and Accessing Class Members
- Logically, it may seem that objects may be quite larger because they contain data and functions.
- Physically, this is not true. Applying sizeof to a class name or to an object of that class will report size of class' data only. This is because the compiler creates different copies of class' data for each object because data can vary among objects. However, the compiler creates only one copy of member functions to be shared by all objects of that class. It can be shared because function code is non-modifiable (also called re-entrant code or pure procedure). Data is placed in memory when objects are defined.
- A class' data members and member functions belong to that class' scope
- Non member functions have file scope
- Within a class scope, class members are immediately accessible by all of that class' member functions and can be referenced by name. Outside class scope, class members are referenced through one of the handles on an object - an object name, a reference or a pointer to an object.
- An implicit handle is inserted by t he compiler on every reference to a data member or member function in an object.
- Member functions of a class can ONLY be overloaded by other member functions of the class. Include prototype for each overloaded function in class definition and provide a separate function definition for each version.
- Variables defined in member functions have function scope.
- If class data also contains variable with same name then this local variable will hide class scope variable. To access class scope variable, use :: operator. Hidden global variables can be accessed using unary scope resolution operator.
- To access members of a class, use dot operator with object name or reference and arrow operator with pointer to object.
Separating Interface from Implementation
- Keep class declaration in a header file to be included by any client who want to use the class
- Implementation is kept in a separate source file
- Clients don't need source code; they need only object code of class implementation. This way no proprietary information is revealed by provided class libraries.
- Private members are not accessible but visible, thereby provide hint about implementation
- Information that is internally used by class and not required by class' clients should be kept in separate unpublished files. <---Principle of Least Privilege
- Use #ifndef, #define and #endif preprocessor directives to prevent header files from being included more than once in a program like
Controlling Access to Members
- Use access specifiers public, private and protected to enforce information hiding & the principle of least privilege
- Don't use an access specifier multiple times
- Keep public members first which acts as public interface
- Private members can only be accessed by member functions or friend classes. All other accesses results in syntax error.
- Client of a class can be any member function of other class or a global function.
- In struct, all members are public by default whereas in class, they are public. Using explicit access specifier is a good practice.
- 'Access functions (set/get)' are used to read or modify the value of private data members.
Advanatges of set functions
- Provide data validation capabilities such as range checking to ensure that the value is set properly.
- Translate between the form of data used in the interface and form used in implementation.
Advantages of get functions (also called query functions)
- Need not expose the data in 'raw' format
- Can edit the data and limit the view of the data the client will see
- Get/set functions are not required for every private member
- Making data member private and providing public member access functions facilitates debugging because problems with data manipulation are localized to either the class' member functions or the friends of the class.
- Set/Get make the data public. It is good from software engineering point of view as get and set put required constraints
- Such functions should also provide feedback to client for any wrong setting etc. //elaborate
Access Functions and Utility Functions
- Not all member functions need to be public to serve as part of a class interface. Some of these can be private to serve as utility functions to other functions of the class.
- Predicate functions test the truth or falsity of conditions e.g. isEmpty() or isTrue() for container class - class capable of holding many objects such as linked list, stack or queue
- Utility functions also called helper functions support the operation of the class' public member functions. They are not intended to be used by clients of a class.
- Once a class is defined, creating and manipulating objects of that class usually involves issuing only a simple sequence of member functions calls-few, if any, control structures are needed. By contrast, it is common to have control structures in the implementation of a class' member functions.
Initializing class objects: Constructors
- It is good to initialize all data members of a class before using member function.
- Such initialization can be done in default constructor, overloaded constructors or through set functions after object is created. It cannot be done in class definition.
Using default arguments with constructors
- A programmer-supplied constructor that default all its arguments (or explicitly requires no arguments) is also a default constructor i.e. a constructor that can be invoked with no arguments.
- There can be only one default constructor per class
- Syntax for default arguments in constructor can be:
- If there is an access function doing same initialization as done by constructor, then it is better to call that access function from constructor passing arguments to it. Using data members before initializing them properly can cause logic errors. This way 'Avoid Repeating Code' is followed, maintenance becomes easy by reducing likelihood of programming error when altering the implementation.
- Performance of a constructor is enhanced by explicitly declaring the constructor inline or by defining the constructor in class definition.
- Declare default function arguments only in function prototype within the class definition in header file
- Specifying default initializers for the same member function in both header file and member function definition is a syntax error.
- Any change to default arguments of a method requires the client code to be re-compiled. It islikely that he default argument values will change, use overloaded functions instead. Thus, if the implementation of a member function changes, the client code need not be recompiled.
- If no constructor is defined the compiler creates a default constructor; however it does not creates perform any initialization, so when the object is created, it is not guaranteed to be in a consistent state.
- It is possible for a class not to have a default constructor if any constructors are defined
- Declaration: ~className( ); <--- No arguments, return types and return values
- A class may have only one destructor - destructor overloading is not allowed
- Destructor is called automatically when an object is destroyed. E.g. for automatic objects when program execution leaves the scope in which an object of that class was instantiated. The destructor does not actually destroy the object - it performs termination house-keeping before the system reclaims the memory so that memory may be re-used to hold new objects.
- Destructors are appropriate for classes whose objects contain dynamically allocated memory (for arrays & strings for e.g.) for de-allocation of storage.
When Constructors and Destructors are called
- Called automatically.
- The order in which these function calls are made depends on the order in which execution enters & leaves the scope in which objects are instantiated.
- Generally, destructors are called in reverse order of the constructor calls
- However, the storage class of objects can alter the order in which the destructors are called.
- Constructors are called for objects defined in global scope before any other function (including main) in that file begins execution (although the order of execution of global object constructors between files is not guaranteed.
- Corresponding destructors are called when main terminates or the exit function is called.
- Destructors are not called for global objects if the program is terminated with a call to function abort.
- Constructors are called for automatic local objects when execution reaches the point where the objects are defined.
- Corresponding destructors are called when the objects leave scope i.i. block in which they are defined exists.
- Destructors are not called for automatic objects if the program is terminated with a call to functions exit or abort.
- Constructors are called for static local objects only once when execution first reaches the point where the objects are defined.
- Corresponding destructors are called when main terminates or the exit function is called.
- Destructors are not called for static objects if the program is terminated with a call to function abort.
Using Data Members and Member Functions
- Advantages of accessing private data through Get/Set
- Protects the data members from receiving invalid values
- Also insulates clients of the class from the representation of the data members. Thus, if the representation of the data changes for some reason (typically to reduce the amount of storage required or to improve performance), only the member functions need to change as long as the interface provided by the member functions remains the same. The clients may, however, need to be recompiled.
A subtle Trap: Returning a Reference to a Private Data Member
- Never have a public member function return a non-const reference (or a pointer) to a private data member. Returning such a reference violates the encapsulation of the class. In fact, returning any reference or points to private data still makes the client code dependent on the representation of the class' data. So, returning pointers or references to private data should be avoided.
Assignment by Default Memberwise Copy
- '=' can be used to assign an object to another object of the same type.
- It is by default performed by memberwise copy-each member of one object is copied (assigned) individually to the same member in another object.
- Memberwise copy can cause serious problems when used with a class whose data members contain dynamically allocated storage. However, operator overloading can be used in this case.
- Objects, by default, are passed by call-by-value. (Compare with call-by-reference, security, performance, use of const)
- Objects can be used function arguments
- Software is increasingly being constructed from existing, well-defined, carefully tested, well-documented, portable, widely available components (class libraries). Software re-usability speeds the development of powerful, high quality software. RAD makes use of components.