CS 202 Fall 2013 > Notes for Thursday, October 10, 2013 |
CS 202 Fall 2013
Notes for Thursday, October 10, 2013
Object-Oriented Programming: Introduction [15.1–15.5]
Object-Oriented Programming
Object-oriented programming (OOP) is a programming paradigm based on the following ideas.
- Data is primary. Instead of a program being made mostly of functions, it is made mostly of objects: data that knows how it is to be dealt with.
- We can use data without knowing about its type or implementation. The data will behave according to its type. This is called polymorphism.
In C++, polymorphism is enabled through the mechanisms of inheritance and virtual functions. We look at inheritance today and virtual functions next time.
Inheritance
Inheritance is a way of creating new classes
from existing classes.
Suppose we have a class X
.
[C++]
class Y : public X { ... };
This makes a new class Y
based on X
.
We say that X
is the base class,
while Y
is the derived class.
The “public
” indicates what status
the public members of X
have in class Y
.
(We almost always use public
inheritance,
but C++ also has protected
and private
inheritance;
look into those if you want.)
In fact, an object of type Y
will
contain an object of type X
.
The members of that X
object
may be used as if they are members of Y
.
Inheritance should express an “is-a”
relationship.
For example, above we should be able to say that
an X
is a Y
.
A standard example of this involves kinds of shapes.
[C++]
class Shape { // Base class ... }; class Triangle : public Shape { // Derived class #1 ... }; class Square : public Shape { // Derived class #2 ... }; class Circle : public Shape { // Derived class #3 ... };
We would generally expect the above to work well, since a triangle is a shape, a square is a shape, and a circle is a shape.
Protected Members
Members that are public
may be accessed
by any function.
Members that are private
may be accessed
only by functions that are either members or friends
of the class.
Even derived-class objects cannot access private members.
A third category is protected
.
These members are almost private
;
they can also be accessed by the derived class.
In other words, protected
members
can be accessed by members and friends of the class
and members and friends of derived classes.
Inheritance, Constructors, and Destructors
Recall that a derived-class object has a base-class object sitting in it. The base-class object is constructed before any derived-class constructor is executed. As with member constructors, we can pass parameters to base-class constructors. When we do this, we write as if a derived-class object has a member whose name is the base class.
[C++]
class X { public: X(int a, const string & b) :_a(a), _b(b) {} private: int _a; string _b; }; class Y : public X { public: Y(int a, const string & b, double c) :X(a, b), // Pass a, b to base-class ctor _c(c) // Pass c to member ctor {} private: double _c; };
Members and base-class objects will be destroyed in the opposite order from their creation. Since the base-class constructor is called before the derived-class constructor, the base-class destructor will be called after the derived-class destructor.
Redefining Base-Class Members
We can redefine a base-class member by making a derived-class member of the same name. This hides the base-class member.
However, we can still access the base-class member
by prefixing its name with
“BASE_CLASS::
”.
[C++]
class X { public: void print() const { cout << "X print" << endl; } }; class Y : public X { public: void print() const { cout << "Y print" << endl; } }; int main() { X x; Y y; x.print(); // Outputs "X print" y.print(); // Outputs "Y print" y.X::print(); // Outputs "X print" }
Class Hierarchies
We can have many classes derived from a single base class. We can also derive new classes from these derived classes. All these classes together form a class hierarchy.
Typically, a class hierarchy has just two levels. We have a single base class from which all other classes are derived. We never create an object of the base class (indeed, we usually make the creation of such objects impossible, by making the base class abstract; more about this next time). Rather, we use the base class to specify an interface that the derived classes implement.
We create objects of the derived classes, but we use them as if they are base-class objects (we will cover how to do this next time, too).
For today’s lab work, see the 10/10 Challenge.