120 likes | 409 Views
Classes in C++. C++ originally called "C with classes": Swedish connection: Bjarne Stoustrup borrowed from Simula (’67) Simulating classes of real world objects C++ continues to evolve: Version 1.0 released by AT&T in 1986 Version 2.0 in 1990 (added multiple inheritance)
E N D
Classes in C++ • C++ originally called "C with classes": • Swedish connection: Bjarne Stoustrup borrowed from Simula (’67) • Simulating classes of real world objects • C++ continues to evolve: • Version 1.0 released by AT&T in 1986 • Version 2.0 in 1990 (added multiple inheritance) • Version 3.0 in 1992 (templates) • ANSI standard in 1996 (exception handling, run time type info) • C++ became dominant OOPL in early 90's • Now Java and C# challenge • A class extends the C++ type system: class Account { //creates a new type }; //Note: you need this semi-colon in C++ Account a1,a2; //define variables of type Account
C structs • A data structure for dates in C: struct Date { int month, day, year; }; int set(struct Date*, int m, int d, int y); int print(struct Date*); • What’s the problem? • No information hiding • No way to control access to data (obscure side effects) • No way to prevent assigning an illegal value to month • Changing representation of Date breaks all client code
C++ structs • C++ provides for closer coupling of data and functions: struct Date { int month, day, year; void set(int m, int d, int y); void print(); //implement elsewhere }; • Invoke functions with variable . memberFunction(): Date today; //In C++, structs automatically define types today.set(9,29,1953); today.print(); • Now we have data abstraction: • Procedural abstraction hides details of code in functions • Data abstraction couples data structure and functions • Still, no information hiding: today.set(50,-10,0);
C++ adds class • C++ adds new keywords to support information hiding: class Date { int month, day, year; public: void set(int m, int d, int y); void print(); //implement elsewhere }; • Members after public: are visible to clients: Date today; today.print(); today.month = 50; //is this legal? • Members after class are by default private
Member functions • What can we add to Date to allow access to month? class Date { int month, day, year; public: void set(int m, int d, int y); void print(); //implement elsewhere int getMonth() { return month; } }; cout << today.getMonth(); //outside class Date • Pros and cons of this approach? • inline function is efficient, though it tends to break information hiding • Let’s define set() and protects the month data: void Date :: set(int m, int d, int y) { assert(m >= 1 && m <= 31); month = m; }
Inheritance (class derivation) • class Account generalizes many kinds of bank accounts: checking, savings, etc. • C++ class derivation captures this generation: class Checking : public Account { public: Checking(float balance); Checking(); //default constructor }; • : denotes derivation—Checking inherits from Account • publicderivation denotes subtype inheritance • Account’s public methods accessible to instances of Checking Checking myChecking(200); //Checking constructor myChecking.getBalance(); //Account function
OOP = Data abstraction + inheritance + dynamic binding • Polymorphism: a function can mean different things at runtime • Dynamic binding: defer function binding to a subtype until runtime • Suppose we want to draw a heterogeneous collection of shapes? class Point { ... }; //a Point has x and y coordinates class Shape { protected: //accessible to subclasses but otherwise private Point center; //all Shapes have a center Point public: Point where() { return center; } virtual void move(Point to) //virtual can be overridden { center = to; draw(); } // by derived classes virtual void draw()=0; //a "pure" virtual function //draw() must be implemented by derived classes //... }
Subclasses override virtual functions class Triangle: public Shape { Point sw, se, top; //Three points define triangle public: Triangle(Point a, Point b, Point c) : sw(a), se(b), top(c) {} draw() //implementing pure virtual function { put_line(sw,top); //draw line from sw to top put_line(top,se); //draw line from top to se put_line(se,sw); //draw line from se to sw } }; class Circle : public Shape { int radius; public: Circle(Point a, int r) : center(a), radius(r) {} draw(); //draw a circle using center and radius };
Calling a virtual function { //Construct some shapes Shape aShape; //illegal--why? Circle c(Point(20,30),7); //legal--what does it do? //Create an array of various shapes Shape* shapes[10]; //Why is this legal? shapes[0] = new Circle(Point(20,30),7); //assign a Circle shapes[1] = new Triangle(Point(50,50),Point(30,30),Point(40,40)); //... maybe assign other shapes, Rectangles, Squares, etc. for (int i=0; i < 10; i++) //draw all the shapes shapes[i]->draw(); //each shape draws itself! } • Why do we say that elements of shapes array are polymorphic? • How does polymorphic design support Open-Closed principle?
Why dynamic binding? • What kind of code does dynamic binding avoid? • Avoids lots of switch statements, e.g.: switch (shapes[i]->isa) //each Shape derived class has an isa data member { case(triangle) Triangle::draw(); //test enumeration case(circle) Circle::draw(); //run specific draw() // ... } • Why is the dynamic binding version better for big, growing programs?