cs11 – introduction to c++donnie/cs11-old/cs11-cpp-lec7.pdf · extending fruit make an...

29
CS11 – Introduction to C++ Fall 2006-2007 Lecture 7

Upload: others

Post on 22-Jun-2020

4 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

CS11 – Introduction to C++

Fall 2006-2007Lecture 7

Page 2: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Today’s Topics

Classes and Class-Inheritance

Page 3: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Fruit Salad

Create a Fruit class:class Fruit {string color;int seeds;

public:Fruit() : color(""), seeds(0) { }Fruit(string col, int s) : color(col), seeds(s) { }

int getSeeds() const { return seeds; }string getColor() const { return color; }void print() const {cout << "I am a Fruit!" << endl;

}};

Page 4: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Using Your Fruit Class

Now, make different fruit instances:Fruit pear("green", 10); // pear is a FruitFruit orange("orange", 25); // orange is a Fruit

pear.print();orange.print();

The program outputs:I am a Fruit!I am a Fruit!

Now you want to know if the orange is peeledBut Fruit doesn’t have a way to represent that!And pears don’t have peels!

Page 5: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Extending Fruit

Make an Orange class that extends FruitAn orange is a fruitThe Orange class will have Fruit’s characteristicsIt will also add more features – state, functionalityOrange is a specialized version of Fruit

New terminology:Fruit is the superclass/base class/parent classOrange is the subclass/derived class/child class

Page 6: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

The Orange Class

Now we create our Orange class:class Orange : public Fruit {bool peeled; // True if peel has been removed

public:Orange() : peeled(false) { }

bool isPeeled() const { return peeled; }void peel() {if (peeled)throw logic_exception("Already peeled!");

peeled = true;}

};

Page 7: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Making Oranges

Orange has new functionality, but also has Fruitmembers:

Orange o;

cout << "This orange has " << o.getSeeds()<< "seeds." << endl;

if (!o.isPeeled()) {cout << "Commencing peel removal..." << endl;o.peel(); // Peel the orange.

}

Page 8: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Oranges are Fruits!

Anywhere we use Fruit, can also use OrangeFruit *pf1 = new Fruit(); // OKFruit *pf2 = new Orange(); // Also OK!

Orange is also a FruitOrange also has members that Fruit has

Converse isn’t true:Orange *po1 = new Orange(); // OKOrange *po2 = new Fruit(); // Compiler error!

A Fruit isn’t an OrangeFruit doesn’t have Orange’s members

For example, you can’t peel a Fruit.

Page 9: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Private Member-Variables

Fruit is declared like this:class Fruit {string color;int seeds;...

What access-level are color and seeds?private is default access-level for classes.

Can Orange do this?void Orange::removeSeeds() {seeds = 0;

}

No! Only the class itself can access its private members.Produces a compiler-error.

Page 10: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

The protected Access-Modifier

To make members accessible to subclasses, use protected access-modifierChange Fruit declaration to:

class Fruit {protected: // Make accessible to subclasses!string color;int seeds;...

Now Orange can access the Fruit variablesvoid Orange::removeSeeds() {seeds = 0; // No compiler errors!

}

Page 11: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

private or protected ?

What should be private?What should be protected?No hard-and-fast rule. Opinions vary!Some suggestions:

In general, make parent-class members private, until you discover the need to manipulate them from the child class. Then make them protected.If parent class manages complicated structures, make those things private. Child classes could mess them up!

Page 12: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Overriding Parent-Class Functions

Child classes can override parent-class functionsChild class is replacing parent-class functionality, or specializing it in some way.

Orange wants to say it’s an orange now.class Orange : public Fruit {...void print() const { // Override Fruit::print()cout << "I am an Orange!" << endl;

}};

Now, calling print() on an Orange instance will printI am an Orange!

Page 13: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Calling Parent-Class Functions

A child class can still call the parent-class version of a function

Just use the qualified name of the function.If Orange also wanted to call Fruit::print()

class Orange : public Fruit {...void print() const {cout << "I am an Orange!" << endl;

// Call parent-class version of print()Fruit::print();

}};

Page 14: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Fruits and Oranges

You write and run this code:Fruit f;Orange o;

f.print();o.print();

What does it print?I am a Fruit!I am an Orange!

Page 15: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Fruits and …

Then you try this code:void printFruit(const Fruit &fr) {

fr.print();}...Fruit f;Orange o;printFruit(f);printFruit(o); // An orange is a fruit.

What does this print?I am a Fruit!I am a Fruit!

Page 16: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Yay, Another Fun C++ Pitfall

By default, C++ uses the variable’s type to know what function to call!

…not the type of the object that the variable refers to!

void printFruit(const Fruit &fr) {fr.print();

}

fr has type Fruit, so Fruit::print() is called.(Yes, even when fr refers to an Orange.)Type of the fr variable is called its static type

It is specified in the source code, and is known at compile-time

Page 17: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Virtual Functions

Enter the virtual keyword.virtual tells C++ to call the member function based on what is referred to, not on the type of the reference

Update Fruit’s declaration:class Fruit {...virtual void print() const {cout << "I am a Fruit!" << endl;

}};

Same with Orange. (Not required, but helps readability.)Now your program prints the expected result:

I am a Fruit!I am an Orange!

Page 18: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

How Does This Work??

How does C++ know what function to call?Declaring the function virtual causes C++ to store a pointer to each object’s version of the function.

The object itself knows what print() function to call.

You create a Fruit:Fruit::print() is stored.

You create an Orange:Orange::print() is stored.

Fruitseedscolor

10"green"

print() Fruit::print()

Orangeseedscolor

25"orange"

print() Orange::print()

peeled false

Page 19: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

The Cost of Virtual Functions

With virtual functions, C++ looks up what function to call, then calls it.

Extra lookup for each call!Slower, takes more space.

With non-virtual functions:C++ assumes object has same type as the variable referring to it.Faster – no extra lookup. But, more confusing!

Only declare functions virtual when you expect them to be overridden.

Orangeseedscolor

25"orange"

print() Orange::print()

peeled false

Page 20: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Destructors!

What about this code:Fruit *pf1 = new Fruit();Fruit *pf2 = new Orange();...delete pf1; // Clean up my fruit.delete pf2;

What destructors are called?Both call Fruit::~Fruit()

Page 21: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Most Important Lesson of C++!

C++ Standard says that deleting a derived class through a base-class pointer, with a nonvirtualdestructor, results in undefined behavior.

Usually only the base-class destructor is called……but anything could happen!

Solution:Give every base class a virtual destructor.Then C++ will do the Right Thing for you.

Corollary:If a class won’t be subclassed, don’t give it a virtual destructor.Virtual functions use up extra room in each instance.

Page 22: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Abstract Functions

Some base classes just declare behavior, but don’t define it

Concept represented by base class is too general to be able to define any reasonable behaviorBase class is intended to be extended

The base class defines abstract functionsBase class can’t be instantiated or used directly

Some of the class’ behavior hasn’t been defined!Subclasses provide the implementationSubclasses are instantiated and used

Page 23: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Pure-Virtual Functions

Functions are declared abstract by making them pure virtualExample:

// Generic build task.class Task {...virtual bool run() = 0; // pure virtual

};// Task that compiles source code.class CompileTask : public Task {...virtual bool run() { ... /* compile */ }

};

run() is not defined in Task, only declared.Subclasses can provide their own definitions of run()

Page 24: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Pure-Virtual Functions

Trying to instantiate Task gives a compiler errorTask *pt = new Task(); COMPILE ERROR

Can still have variables of type Task& or Task*Task *pt = new CompileTask(conf); OK!

Especially useful when providing generic processing capabilities for a variety of specialized objects

void doTasks(vector<Task*> tasks);

doTasks can use the generic Task interfaceEach task-object has its own implementation of Task::run()

Page 25: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Using Pure-Virtual Functions

Some base-classes have some pure-virtual functions

The base-class provides some implementation…The subclass provides the missing pieces

An “interface” is a base class with all pure-virtual functions

The base class is only declaring behavior, but provides no implementation at allThis concept of an “interface” is more explicit in other languages

Page 26: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

Parent-Class Constructors

Fruit also has a two-argument constructor:Fruit(string col, int s) : color(col), seeds(s) { }

Uses initializer-lists to construct member-variablesWant to give Orange a similar constructor:

Orange(string col, int s, bool p) :color(col), seeds(s), peeled(p) { }

This won’t work! Gives you a compiler error.Child class isn’t allowed to initialize parent-class member variables this way

Orange constructor should call Fruit constructor insteadOrange(string col, int s, bool p) :Fruit(col, s), peeled(p) { }

Page 27: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

More Parent-Class Constructor Tips

Sometimes a parent class doesn’t have a default (no-argument) constructorIn these cases, subclasses must call the parent-class constructor in the initializer listIf called, the parent-class constructor must appear first in initializer list!

Page 28: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

The OOP Concepts (again)

So far, we have seen:Encapsulation: hiding implementation detailsAbstraction: presenting a simple, high-level interface

Class-hierarchies introduce two more:Inheritance: a child class gets its parent class’members/behavior

…and a child-class can customize parent-class behaviorPolymorphism: calling a function on an object can exhibit different behaviors, based on the object type

In C++, this requires the use of virtual functions

Page 29: CS11 – Introduction to C++donnie/cs11-old/cs11-cpp-lec7.pdf · Extending Fruit Make an Orangeclass that extends Fruit An orange is a fruit The Orange class will have Fruit’s characteristics

This Week’s Lab

Homework should be pretty straightforwardLots of class-inheritance stuff!