360 likes | 463 Views
Version 1.0. Programming Techniques Course. Version 1.0. Chapter 3A – Data Abstraction. Table of contents. Expressing Our World via OO Expending our programming language to support those new needs User-defined type Class declaration, definition, implementation Object creation
E N D
Version 1.0 Programming Techniques Course
Version 1.0 Chapter 3A –Data Abstraction
Table of contents • Expressing Our World via OO • Expending our programming language to support those new needs • User-defined type • Class declaration, definition, implementation • Object creation • Encapsulation and interfaces • Access control
What Do We Need From OO? • Express our world via • Objects • Responsibilities • Operations / capabilities • Inter-Relationship • Cardinality / Multiplicity • Hierarchies • Generic approach via interfaces • Objects invoking one another via message passing • Achieve de-coupled, self-maintained instances • Via implementation hiding • With well defined interfaces
What Do We Expect from an OO Language? • User-Defined types • Define new types, to support our new “language” • Same behavior as had been with built-in types • int a=1, b=2, c; • c= a+b; • Expand to user-defined types • String s1 = “C++ “; • String s2 = “Class”; • String s3; • S3 = s1 + s2; • Hide implementation • What do we mean by “hide”?
Declaration Of a Class class String { char* m_str; public: char* GetString(); void SetString(char* newStr); }; String.h Declaration of a class We can use those services • The implementation is not important for us, as users of the class • It is important for us to understand which services we get from the class, and its precise usage
Object Creation - Instantiation void main() { String s1, s2; s1.SetString(“hello”); s2.SetString(“bye”); printf(“s1 is: %s, s2 is: %s\n”, s1.GetString(), s2.GetString()); } main.cpp Using the String class • Creating 2 objects • Setting them with values, via SetString() method • What is the internal representation of s1 and s2 ? • Do we care, as users of the class? • Accessing their values, via GetString() method, returning their value, and printing them in an old manner
Definition Of A Class class String { char* m_str; public: char* GetString(); void SetString(char* newStr); }; String.h Declaration of a class • char* String::GetString() { • return m_str; • } • void String::SetString(char* newStr) { • int len=strlen(newStr); • m_str = new char[len+1]; • strcpy(m_str, newStr); • } String.cpp Definition of a class
Object Creation - Instantiation • Lets add another method • int String::CompareString(String* strToCompare) { if (strcmp(strToCompare->m_str, m_str)==0) • return 1; else • return 0; • } void main() { String s1, s2; s1.SetString(“hello”); s2.SetString(“bye”); printf(“s1 is: %s, s2 is: %s\n They are ”, s1.GetString(), s2.GetString()); if (s1.CompareString(&s2)==1) printf(“equivalent\n”); else printf(“non-equivalent\n”); }
Object Creation – Cont’d class String { char* str; int len; public: char* GetString(); void SetString(char* newStr); }; • Assume that most comparisons in our applications are FALSE. • Suggest a more efficient solution to the above implementation
Object Creation – Cont’d char* String::GetString() { return m_str; } void String::SetString(char* newStr) { m_len=strlen(newStr); m_str = new char[m_len+1]; strcpy(m_str, newStr); } int String::CompareString(String* strToCompare) { if (len != strToCompare->m_len) return 0; else if (strcmp(strToCompare->str, str)==0) return 1; else return 0; }
Encapsulation • Do we need to change main? • Why not? • ENCAPSULATION !!! Implementation Hiding !!! • We touched internal presentation only !! • We have not touched the exposed interface !! • We have kept the rule of IMPLEMENTATION HIDING !! • Major OO Concept for better SW Engineering !!
C++: Limiting data visibility • Visibility of class members limited in class declaration • private– accessible only within the class • protected– accessible only within the class and classes that inherit from it • public– accessible anywhere • private is the default access level class C{ int i; //private by default private: int j; protected: int k; public: int l;} • This is just the basics, more to come…
Encapsulation and Access Control • Expose minimum to clients • Do not expose internal representation • This is enforced by the private keyword • Client cannot access private members • Default access is private (that is why we did not have to write the keyword private before the data members) • Expose interface to clients • Enforced by the public keyword • There is more to accessibility • We will talk about it later
Data Abstraction - summary • Define a type and operations on it • Like built-in types: int, float, … • Conceal data and implementation • Use access modifiers • private, protected, public • Why? • Easier to design and implement • Localizes future modifications
Issues • Will it work? 1: char* String::getString(){return chars;} 2: void String::setString(char* value){ 3: length = strlen(value); 4: chars = new char[length+1]; 5: strcpy(value, chars); 6: } 7: int String::equals(String *other){ 8: if (length != other->length) 9: return 0; 10: if (strcmp(chars, other->chars) == 0) 11: return 1; 12: return 0; 13: }
Issues • Nullity checks • Before using a pointer, ask if it is null • Always check the parameters 1: char* String::getString(){return chars;} 2: void String::setString(char* value){ if (value == NULL) return; 3: length = strlen(value); 4: chars = new char[length+1]; 5: strcpy(value, chars); 6: } 7: int String::equals(String *other){ if (other == null) return 0; 8: if (length != other->length) 9: return 0; if (length == 0) return 1; //if length != 0, then chars != NULL 10: if (strcmp(chars, other->chars) == 0) 11: return 1; 12: return 0; 13: }
Version 1.0 Chapter 3A –Object ConstructionAnd Overloading
Table of contents • Lifetime Of Variables • Object construction • Constructor • Destructor • Overloading a Constructor • Parameter matching
Lifetime Of Variables • Lifetime of an object • Lets recall lifetime in “C” • Automatic • On the stack • Allocated when entering scope • What is a scope? • Static • Global • Static within module • Static within scope • Dynamic • Allocated on heap Global Code Heap Stack
Initialization • Similar mechanism is used for objects • Important to distinguish between • Physical memory allocation • Logical variable initialization • When physical memory is set aside for an object, it is not initialized • Having “garbage” data, from previous memory occupation • We need to initialize this memory to a stable state, with “good” values, for proper execution
Object Creation • Object creation • When an object is created, an initialization method is invoked, to bring the object to its invariant state • This method is called a Constructor • It is a special method, invoked automatically, when an object is born (not physically allocated memory) • It has the same name as the name of the class, that is how a compiler distinguishes it from other methods.
Definition Of A Class class String { char* m_str; int m_len; public: String(); char* GetString(); void SetString(char* newStr); }; String.h Declaration of a class • String:: String() { • m_len = 0; m_str = NULL; • } • char* String::GetString() { • return m_str; • } • void String::SetString(char* newStr) { • … • } String.cpp Definition of a class
Destruction • Object destruction • When an object is destroyed • Going out of scope (for automatic variables) • Deallocated globally • Deallocated dynamically (delete operator) • This method is called a Destructor • It is a special method, invoked automatically, when the life cycle of an object ends • It has the same name as the name of the class with a preceding ~
Definition Of A Class class String { char* m_str; int m_len; public: String(); ~String(); char* GetString(); void SetString(char* newStr); }; String.h Declaration of a class • String::String() { • m_len = 0; m_str = NULL; • } • String::~String() { • m_len = 0; • free(m_str); • m_str = NULL; • } • … String.cpp Definition of a class
Defaults • If I do not declare a constructor, the compiler will generate one for me • If I do not declare a destructor, the compiler will generate one for me • If I do not declare a copying semantics, the compiler will generate one for me • Assignment • Copy construction • We will talk about it more later
Defining Additional Ctors • The Empty Ctor (no parameters) is called the default Ctor • It is called when we define an object in the following manner • String s; • If we define the object with initialization data, a different Ctor is invoked, for instance • String s=“hello”; • In this case a Ctor with the parameter char* is invoked
Function overloading • Function overloading: • Several functions • Same name • Different parameters • In C: prohibited • In C++: allowed • Also for constructors • At each call site, compiler finds the target function by matching the parameters
Definition Of A Class String.h Declaration of a class class String { char* m_str; int m_len; public: String(); String(char*); ~String(); char* GetString(); void SetString(char* newStr); }; String.cpp Definition of a class • String::String() { • m_len = 0; m_str = NULL; • } • String::String(char* str) { • m_len = strlen(str); • m_str = new char[m_len+1]; • strcpy(m_str, str); • } • String::~String() { • m_len = 0; • free(m_str); • m_str = NULL; • } • … We have here 2 functions with the same name !! How is it possible ?
Overloading • Overloading is declaring the same function name more than once • In “C” this would result in compilation error • C++ permits this • If the function have different parameters • It performs “name mangling” (decoration) to produce different symbols for each function • Upon method call, resolving should be taken to decide, which function should be actually called • The caller “sends a message” • The actual method is invoked after the compiler performed the suitable matching
How is it done? • Name mangling • Compiler encodes parameter types in the method name
Parameter Matching • In C++, parameter matching is performed, in the following order • Exact matching is examined • Built in type matching • User defined matching • If suitable Ctor exists • Casting is defined • In our example … • Parameter passing • By value • By pointer • By reference (we will talk more about it later…)
Using constructors: String Calls String() Calls String(“Hi”) Calls String(“Hello”) int main(){ String str; String str2(“Hi”); String str3 = “Hello”; foo (str3); //foo declared as foo(String) } Calls copy-constructorString(const String& other)
Copy-constructors • Single parameter – reference to the copied object • class X{ public X(const X& x); } • Called by the compiler • When an object is initialized using another object of the same class • X x; X x1(x); • When an object is passed by value • void foo(X xparam);foo(x); • If no copy-constructor defined, compiler adds one • Bitwise copy of the copied object • Not always fits
String copy-constructor char* String::getString(){return chars;} String::String(const String& other){ length = other.length; chars = new char[length+1]; strcpy(other.chars, chars); } String.cpp