toward a common intuition and reusable testing methodology€¦ · 1. the .cpp file includes its .h...

Post on 07-Aug-2020

3 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

1

Proper Inheritance

John Lakos

Tuesday, May 10, 2016

2

Copyright Notice

© 2016 Bloomberg L.P. Permission is granted to copy, distribute, and display this material, and to make derivative works and commercial use of it. The information in this material is provided "AS IS", without warranty of any kind. Neither Bloomberg nor any employee guarantees the correctness or completeness of such information. Bloomberg, its employees, and its affiliated entities and persons shall not be liable, directly or indirectly, in any way, for any inaccuracies, errors or omissions in such information. Nothing herein should be interpreted as stating the opinions, policies, recommendations, or positions of Bloomberg.

3

Abstract All essential behavior of our software must be documented, and yet there are

important advantages, with respect to development, verification and testing,

performance, and stability, for leaving the behavior for some combinations of

inputs and initial conditions undefined. What is and is not defined behavior

should therefore be readily discernible from the contract, especially when

creating contracts that must span classes related by inheritance.

In this two-part talk, we begin by reviewing components, interfaces and

contracts in general, and the significance of narrow versus wide contracts. In

the second part, we go on to explore three kinds of inheritance: (1) Interface

Inheritance resulting from pure-virtual functions, (2) Structural Inheritance

resulting from non-virtual functions, and (3) Implementation Inheritance

resulting from non-pure virtual functions. Proper contracts involving each of

these distinct forms have different criteria that must be addressed. The three

kinds of inheritance are compared, and their relative utility is explained.

What's more, several common uses of inheritance that are provably improper

are summarily debunked.

4

What’s The Problem?

5

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional:

6

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional:

• It involves many subtle logical and physical aspects.

7

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional:

• It involves many subtle logical and physical aspects.

• It requires an ability to isolate and modularize logical functionality within discrete, fine-grain physical components.

8

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional:

• It involves many subtle logical and physical aspects.

• It requires an ability to isolate and modularize logical functionality within discrete, fine-grain physical components.

• It requires the designer to delineate logical behavior precisely, while managing the physical dependencies on other subordinate components.

9

What’s The Problem? Large-Scale C++ Software Design is Multi-Dimensional:

• It involves many subtle logical and physical aspects.

• It requires an ability to isolate and modularize logical functionality within discrete, fine-grain physical components.

• It requires the designer to delineate logical behavior precisely, while managing the physical dependencies on other subordinate components.

• It requires attention to numerous logical and physical rules that govern sound software design.

10

Purpose of this Talk

11

Purpose of this Talk

Review:

12

Purpose of this Talk

Review: 1. Components – Our fundamental unit of logical and physical design

13

Purpose of this Talk

Review: 1. Components – Our fundamental unit of logical and physical design

2. Interfaces and contracts (in general)

14

Purpose of this Talk

Review: 1. Components – Our fundamental unit of logical and physical design

2. Interfaces and contracts (in general)

3. Narrow versus Wide contracts (in particular)

15

Purpose of this Talk

Review: 1. Components – Our fundamental unit of logical and physical design

2. Interfaces and contracts (in general)

3. Narrow versus Wide contracts (in particular)

4. Explore these basic ideas in the context inheritance.

16

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

17

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

1. Components (review)

Logical versus Physical Design

What distinguishes Logical from Physical Design?

Logical

physical

18

1. Components (review)

Logical versus Physical Design

What distinguishes Logical from Physical Design? Logical: Classes and Functions

Logical

physical

19

1. Components (review)

Logical versus Physical Design

What distinguishes Logical from Physical Design? Logical: Classes and Functions Physical: Files and Libraries

Logical

physical

20

1. Components (review)

Logical versus Physical Design

Logical content aggregated into a Physical hierarchy of components

a b

c

21

1. Components (review)

Component: Uniform Physical Structure

// component.t.cpp

#include <component.h>

// ...

int main(...)

{

//...

}

//-- END OF FILE --

component.t.cpp

// component.h

// ...

//-- END OF FILE --

// component.cpp

#include <component.h>

// ...

//-- END OF FILE --

component.h component.cpp

component

A Component Is Physical

22

1. Components (review)

Component: Uniform Physical Structure

// component.t.cpp

#include <component.h>

// ...

int main(...)

{

//...

}

//-- END OF FILE --

component.t.cpp

// component.h

// ...

//-- END OF FILE --

// component.cpp

#include <component.h>

// ...

//-- END OF FILE --

component.h component.cpp

component

Implementation

23

1. Components (review)

Component: Uniform Physical Structure

// component.t.cpp

#include <component.h>

// ...

int main(...)

{

//...

}

//-- END OF FILE --

component.t.cpp

// component.h

// ...

//-- END OF FILE --

// component.cpp

#include <component.h>

// ...

//-- END OF FILE --

component.h component.cpp

component

Header

24

1. Components (review)

Component: Uniform Physical Structure

// component.t.cpp

#include <component.h>

// ...

int main(...)

{

//...

}

//-- END OF FILE --

component.t.cpp

// component.h

// ...

//-- END OF FILE --

// component.cpp

#include <component.h>

// ...

//-- END OF FILE --

component.h component.cpp

component

Test Driver

25

1. Components (review)

Component: Uniform Physical Structure

// component.t.cpp

#include <component.h>

// ...

int main(...)

{

//...

}

//-- END OF FILE --

component.t.cpp

// component.h

// ...

//-- END OF FILE --

// component.cpp

#include <component.h>

// ...

//-- END OF FILE --

component.h component.cpp

component

The Fundamental Unit of Design

26

1. Components (review)

Component: Not Just a .h/.cpp Pair

my::Widget

my_widget

27

28

1. Components (review)

Component: Not Just a .h/.cpp Pair

1. The .cpp file includes its .h file as the first substantive line of code.

29

1. Components (review)

Component: Not Just a .h/.cpp Pair

1. The .cpp file includes its .h file as the first substantive line of code.

2. All logical constructs having external linkage defined in a .cpp file are declared in the corresponding .h file.

3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component.

4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration.

30

1. Components (review)

Component: Not Just a .h/.cpp Pair

1. The .cpp file includes its .h file as the first substantive line of code.

2. All logical constructs having external linkage defined in a .cpp file are declared in the corresponding .h file.

3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component.

4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration.

31

1. Components (review)

Component: Not Just a .h/.cpp Pair

We could easily spend 20 minutes on this slide alone!

1. The .cpp file includes its .h file as the first substantive line of code.

2. All logical constructs having external linkage defined in a .cpp file are declared in the corresponding .h file.

3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component.

4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration.

32

1. Components (review)

Component: Not Just a .h/.cpp Pair Achieve

Logical/Physical Modularity

Avoid Global Namespace

Pollution

Enable Efficient Extraction of

Physical Dependencies

1. The .cpp file includes its .h file as the first substantive line of code.

2. All logical constructs having external linkage defined in a .cpp file are declared in the corresponding .h file.

3. All constructs having external or dual bindage declared in a .h file (if defined at all) are defined within the component.

4. A component’s functionality is accessed via a #include of its header, and never via a forward (extern) declaration.

33

1. Components (review)

Component: Not Just a .h/.cpp Pair Achieve

Logical/Physical Modularity

Avoid Global Namespace

Pollution

Enable Efficient Extraction of

Physical Dependencies

For much more see

ADVANCED LEVELIZATION TECHNIQUES

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Polygon

Point

34

Underscore Implies Component-Local Class

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A

Polygon

Point

35

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A

Polygon

Point

36

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A

Uses-in-the-Interface

Polygon

Point

37

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A

Uses-in-the-Interface

Polygon

Point

38

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A

Uses-in-the-Interface

Polygon

Point

39

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface

Polygon

Point

40

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface

Polygon

Point

41

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface

Polygon

Point

42

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Polygon

Point

43

1. Components (review)

Logical Relationships

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Polygon

Point

44

1. Components (review)

Implied Dependency

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Polygon

Point

45

1. Components (review)

Implied Dependency

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Depends-On

Polygon

Point

46

1. Components (review)

Implied Dependency

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Depends-On

Polygon

Point

47

1. Components (review)

Implied Dependency

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Depends-On

Polygon

Point

48

1. Components (review)

Implied Dependency

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Depends-On

Polygon

Point

49

1. Components (review)

Implied Dependency

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Depends-On

Polygon

Point

50

1. Components (review)

Level Numbers

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface Uses in name only

Depends-On

Polygon

Point

51

1. Components (review)

Level Numbers

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface

1

Uses in name only

Depends-On

Polygon

Point

52

1. Components (review)

Level Numbers

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface

1 1

Uses in name only

Depends-On

Polygon

Point

53

1. Components (review)

Level Numbers

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface

1 1

2

Uses in name only

Depends-On

Polygon

Point

54

1. Components (review)

Level Numbers

Shape

PointList

PointList_Link

Is-A Uses-in-the-Implementation

Uses-in-the-Interface

1 1

2 3

Uses in name only

Depends-On

Polygon

Point

55

1. Components (review)

Essential Physical Design Rules

56

1. Components (review)

Essential Physical Design Rules

There are two:

57

1. Components (review)

Essential Physical Design Rules

There are two:

1.No Cyclic Physical Dependencies!

58

1. Components (review)

Essential Physical Design Rules

There are two:

1.No Cyclic Physical Dependencies!

2.No Long-Distance Friendships!

59

1. Components (review)

End of Section

Questions?

1. Components (review)

What Questions are we Answering? • What distinguishes Logical and Physical Design? • What is the first of the (four) fundamental properties of

a .h /.cpp pair that make it a component? • Which of these fundamental properties helps us extract

physical dependencies efficiently? Extra credit: Why? How? • What are the (four) logical-relationship annotations? • Which logical relationship does not imply a physical one? • How do we infer physical relationships (Depends-On)

from logical ones? • What do we mean by the term level number? • What are the (two) quintessential physical design rules?

61

62

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

63

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

64

2. Interfaces and Contracts (review)

Interfaces and Contracts

What do we mean by Interface versus Contract for

• A Function? • A Class? • A Component?

65

2. Interfaces and Contracts (review)

Interfaces and Contracts

Function std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

66

2. Interfaces and Contracts (review)

Interfaces and Contracts

Function std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

Types Used

In the Interface

67

2. Interfaces and Contracts (review)

Interfaces and Contracts

Function std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const; // Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect.

68

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date.

// …

};

69

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date.

// …

};

Public

Interface

70

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date.

// …

};

71

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date.

// …

};

72

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date.

// …

};

73

2. Interfaces and Contracts (review)

Interfaces and Contracts

Class class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date.

// …

};

74

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … };

bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, ‘and’ false otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’.

75

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … };

bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, ‘and’ false otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’.

“Public”

Interface

76

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … };

bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, ‘and’ false otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’.

77

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … };

bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, and ‘false’ otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates no not have the // same value and false otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’.

78

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … };

bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, and ‘false’ otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates do not have the // same value, and ‘false’ otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’.

79

2. Interfaces and Contracts (review)

Interfaces and Contracts

Component

class Date { // … public: // … };

bool operator==(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates have the same // value, and ‘false’ otherwise. Two ‘Date’ objects have the same // value if their respective ‘year’, ‘month’, and ‘day’ attributes // have the same value. bool operator!=(const Date& lhs, const Date& rhs); // Return ‘true’ if the specified ‘lhs’ and ‘rhs’ dates do not have the // same value, and ‘false’ otherwise. Two ‘Date’ objects do not have // the same value if any of their respective ‘year’, ‘month’, and ‘day’ // attributes do not have the same value. std::ostream& operator<<(std::ostream& stream, const Date& date); // Format the value of the specified ‘date’ object to the specified // output ‘stream’ as ‘yyyy/mm/dd’, and return a reference to ‘stream’.

2. Interfaces and Contracts (review)

Preconditions and Postconditions

80

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function

81

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

82

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

83

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Precondition

84

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Precondition For a Stateless Function:

Restriction on syntactically legal inputs. 85

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

86

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Postcondition

87

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Function double sqrt(double value); // Return the square root of the specified ‘value’. // The behavior is undefined unless ‘0 <= value’.

Postcondition

For a Stateless Function:

What it “returns.” 88

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method

89

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method

Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined.

90

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method

Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined.

Postconditions: What must happen as a function of (object) state and input if all Preconditions are satisfied.

91

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Object Method

Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined.

Postconditions: What must happen as a function of (object) state and input if all Preconditions are satisfied.

92

2. Interfaces and Contracts (review)

Preconditions and Postconditions

93

Object Method

Preconditions: What must be true of both (object) state and method inputs; otherwise the behavior is undefined.

Postconditions: What must happen as a function of (object) state and method inputs if all preconditions are satisfied.

Observation By

Kevlin Henny

Note that Essential Behavior refers to a superset of Postconditions that includes

behavioral guarantees, such as runtime complexity.

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Undefined Behavior 94

Not

Undefined

Behavior

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Essential Behavior

Undefined Behavior 95

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Essential Behavior

Undefined Behavior 96

Defined but not

Essential

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

Essential Behavior

Undefined Behavior 97

Defined but not

Essential

Unspecified and Implementation

-dependent

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect. 98

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect. 99

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect. 100

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect. 101

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect. 102

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect.

Any Undefined Behavior?

103

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect.

Any Non-Essential

Behavior?

104

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

std::ostream& print(std::ostream& stream,

int level = 0,

int spacesPerLevel = 4) const;

// Format this object to the specified output 'stream' at the (absolute

// value of) the optionally specified indentation 'level' and return a

// reference to 'stream'. If 'level' is specified, optionally specify

// 'spacesPerLevel', the number of spaces per indentation level for

// this and all of its nested objects. If 'level' is negative,

// suppress indentation of the first line. If 'spacesPerLevel' is

// negative, format the entire output on one line, suppressing all but

// the initial indentation (as governed by 'level'). If 'stream' is

// not valid on entry, this operation has no effect.

Any Non-Essential

Behavior?

105

Hint

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

106

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

Any Undefined Behavior?

107

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

Any Undefined Behavior?

108

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

109

Defined & Essential Behavior

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

Any Undefined Behavior?

110

(Object) Invariants

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

111

(Object) Invariants

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

112

(Object) Invariants

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

113

(Object) Invariants

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

114

(Object) Invariants

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

115

(Object) Invariants

2. Interfaces and Contracts (review)

Preconditions and Postconditions

class Date { // This class implements a value-semantic type representing // a valid date in history between the dates 0001/01/01 and // 9999/12/31 inclusive.

//…

public:

Date(int year, int month, int day); // Create a valid date from the specified ‘year’, ‘month’, and // ‘day’. The behavior is undefined unless ‘year’/’month’/’day’ // represents a valid date in the range [0001/01/01 .. 9999/12/31].

Date(const Date& original); // Create a date having the value of the specified ‘original’ date. // … };

116

2. Interfaces and Contracts (review)

Design by Contract

117

(DbC)

“If you give me valid input*, I will behave as advertised; otherwise, all bets are off!”

*including state

2. Interfaces and Contracts (review)

Design by Contract

118

There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that…

2. Interfaces and Contracts (review)

Design by Contract

Documentation

119

There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that…

2. Interfaces and Contracts (review)

Design by Contract

Documentation

120

There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that…

2. Interfaces and Contracts (review)

Design by Contract

Documentation

121

There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that…

2. Interfaces and Contracts (review)

Design by Contract

Documentation

122

There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that…

2. Interfaces and Contracts (review)

Design by Contract

Documentation

123

There are five aspects: 1. What it does. 2. What it returns. 3. Essential Behavior. 4. Undefined Behavior. 5. Note that…

2. Interfaces and Contracts (review)

Design by Contract

Documentation

124

Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

125

Preconditions: Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

126

Preconditions: RTFM (Read the Manual).

Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

127

Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode).

Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

128

Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode).

Postconditions: Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

129

Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode).

Postconditions: Component-level test drivers.

Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

130

Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode).

Postconditions: Component-level test drivers.

Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

131

Preconditions: RTFM (Read the Manual). Assert (only in ‘debug’ or ‘safe’ mode).

Postconditions: Component-level test drivers.

Invariants: Assert invariants in the destructor.

2. Interfaces and Contracts (review)

Design by Contract

Verification

132

133

Preconditions always Imply Postconditions:

2. Interfaces and Contracts (review)

Contracts and Exceptions

134

Preconditions always Imply Postconditions:

If a function cannot satisfy its contract (given valid

preconditions) it must not return normally.

2. Interfaces and Contracts (review)

Contracts and Exceptions

135

Preconditions always Imply Postconditions:

If a function cannot satisfy its contract (given valid

preconditions) it must not return normally.

abort() should be considered a viable alternative to

throw in virtually all cases (if exceptions are disabled).

2. Interfaces and Contracts (review)

Contracts and Exceptions

136

Preconditions always Imply Postconditions:

If a function cannot satisfy its contract (given valid

preconditions) it must not return normally.

abort() should be considered a viable alternative to

throw in virtually all cases (if exceptions are disabled).

Good library components are exception agnostic (via RAII).

2. Interfaces and Contracts (review)

Contracts and Exceptions

Questions?

2. Interfaces and Contracts (review)

End of Section

137

138

2. Interfaces and Contracts (review)

What Questions are we Answering? • What do we mean by Interface versus Contract for a

function, a class, or a component? • What do we mean by preconditions, postconditions,

and invariants? • What do we mean by essential & undefined behavior? • Must the code itself preserve invariants even if one or

more preconditions of the contract are violated? • What is the idea behind Design-by-Contract (DbC)? • How do we document the contract for a function? • How can clients ensure that preconditions are satisfied? • How do we guarantee that postconditions are satisfied? • How can we test to make sure invariants are preserved? • What must be true if a client satisfies all preconditions?

139

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

140

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

141

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

142

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms:

143

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms:

•Fat Interface (4. Proper Inheritance)

144

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms:

•Fat Interface (4. Proper Inheritance)

•Large (Non-Primitive) Interface

145

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Pejorative terms:

•Fat Interface (4. Proper Inheritance)

•Large (Non-Primitive) Interface

•Wide Contract

146

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

147

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

148

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

How about it must return 0?

149

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s)

{

if (!s) return 0;

// …

}

How about it must return 0?

Wide

150

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s)

{

if (!s) return 0;

// …

}

How about it must return 0?

Wide

Likely to mask a defect

151

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s)

{

if (!s) return 0;

// …

}

How about it must return 0?

Wide

Likely to mask a defect

152

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

153

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: What should happen with the following call?

int x = std::strlen(0);

154

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s)

{

assert(s);

// …

}

Narrow

155

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s)

{

// …

}

Narrow

156

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

int strlen(const char *s)

{

// …

}

Narrow

157

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should

Date::setDate(int, int, int);

Return a status?

158

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should

Date::setDate(int, int, int);

Return a status?

159

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: I “know” this date is valid (It’s my birthday)!

date.setDate(3, 8, 59);

Therefore, why should I bother to check status?

date.setDate(1959, 3, 8);

160

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: I “know” this date is valid (It’s my birthday)!

date.setDate(3, 8, 59);

Therefore, why should I bother to check status?

date.setDate(1959, 3, 8);

161

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: I “know” this date is valid (It’s my birthday)!

date.setDate(3, 8, 59);

Therefore, why should I bother to check status?

date.setDate(1959, 3, 8);

162

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

Returning status implies a wide contract.

163

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

Returning status implies a wide contract.

Wide contracts prevent defending against such errors in any build mode.

164

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

void Date::setDate(int y, int m, int d) { assert(isValid(y,m,d)); d_year = y; d_month = m; d_day = d; }

165

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

void Date::setDate(int y, int m, int d) { assert(isValid(y,m,d)); d_year = y; d_month = m; d_day = d; }

166

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior:

void Date::setDate(int y, int m, int d) { assert(isValid(y,m,d)); d_year = y; d_month = m; d_day = d; }

Narrow Contract:

Checked Only In

“Debug Mode”

167

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: int Date::setDateIfValid(int y, int m, int d) { if (!isValid(y, m, d)) { return !0; } d_year = y; d_month = m; d_day = d; return 0; }

168

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: int Date::setDateIfValid(int y, int m, int d) { if (!isValid(y, m, d)) { return !0; } d_year = y; d_month = m; d_day = d; return 0; }

Wide Contract:

Checked in

Every Build Mode

169

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is

undefined? TYPE& vector::operator[](int idx);

170

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is

undefined? TYPE& vector::operator[](int idx);

• Should what happens be part of the contract?

TYPE& vector::at(int idx);

171

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is

undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract?

TYPE& vector::at(int idx);

172

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is

undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? If it is, then it’s essential behavior!

TYPE& vector::at(int idx);

173

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is

undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? If it is, then it’s essential behavior!

TYPE& vector::at(int idx);

174

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: • What should happen when the behavior is

undefined? It depends on the build mode. TYPE& vector::operator[](int idx);

• Should what happens be part of the contract? If it is, then it’s essential behavior!

TYPE& vector::at(int idx);

175

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero?

176

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be?

177

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be?

if (idx < 0) idx = 0;

if (idx > length()) idx = length();

178

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be?

if (idx < 0) idx = 0;

if (idx > length()) idx = length();

idx = abs(idx) % (length() + 1);

179

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be?

if (idx < 0) idx = 0;

if (idx > length()) idx = length();

idx = abs(idx) % (length() + 1);

180

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be?

if (idx < 0) idx = 0;

if (idx > length()) idx = length();

idx = abs(idx) % (length() + 1);

181

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? If so, what should it be?

if (idx < 0) idx = 0;

if (idx > length()) idx = length();

idx = abs(idx) % (length() + 1);

182

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero?

183

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? Answer: No!

184

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? Answer: No!

assert(0 <= idx); assert(idx <= length());

185

3. Narrow versus Wide Contracts (review)

Narrow versus Wide Contracts

Narrow Contracts Imply Undefined Behavior: Should the behavior for

void insert(int idx, const TYPE& value);

be defined when idx is greater than length() or less than zero? Answer: No!

assert(0 <= idx); assert(idx <= length());

186

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

187

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

Narrow, but not too narrow.

188

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

Narrow, but not too narrow.

Should the behavior for

void replace(int index,

const TYPE& value,

int numElements);

be defined when index is length() and numElements is zero?

189

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

0 1 2 3 4 5

1

2

3

4

0

numElements

index

5 E.g., length() is 5.

?

190

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

0 1 2 3 4 5

1

2

3

4

0

numElements

index

5 E.g., length() is 5.

?

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

191

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

0 1 2 3 4 5

1

2

3

4

0

numElements

index

5 E.g., length() is 5.

?

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

X

192

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

0 1 2 3 4 5

1

2

3

4

0

numElements

index

5 E.g., length() is 5.

?

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

Now a client would have to check for this special case.

X

193

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

0 1 2 3 4 5

1

2

3

4

0

numElements

index

5 E.g., length() is 5.

?

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

Now a client would have to check for this special case.

X

194

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

0 1 2 3 4 5

1

2

3

4

0

numElements

index

5 E.g., length() is 5.

?

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

Assuming no extra code is needed to handle it …

195

3. Narrow versus Wide Contracts (review)

Appropriately Narrow Contracts

0 1 2 3 4 5

1

2

3

4

0

numElements

index

5 E.g., length() is 5.

!

void replace(int index, const TYPE& value, int numElements) { assert(0 <= index); assert(0 <= numElements); assert(index + numElements <= length()); // … }

Assuming no extra code is needed to handle it …

… it is naturally more efficient to allow it.

196

3. Narrow versus Wide Contracts (review)

End of Section

Questions?

197

3. Narrow versus Wide Contracts (review)

What Questions are we Answering? • What do we mean by a narrow versus a wide contract?

– Should std::strlen(0) be required to do something reasonable?

– Should Date::setDate(int, int, int) return a status?

• What should happen when the behavior is undefined? – Should what happens be part of the component-level contract?

• What about the behavior for these specific interfaces: – Should operator[](int index) check to see if index is less than

zero or greater than length()? • And what should happen if index is out of range?

– Should insert(int index, const TYPE& value) be defined when index is greater than length() or less than zero?

– Should replace(int index, const TYPE& value, int numElements) be defined when index is length() and numElements is zero?

• What do we mean by Defensive Programming (DP)?

198

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

199

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

200

4. Proper Inheritance

Three Kinds of Inheritance

201

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

202

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

Public, Protected,

Private?

203

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

Public, Protected,

Private?

204

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

205

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

• Interface Inheritance: – Pure Virtual Functions

206

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

• Interface Inheritance: – Pure Virtual Functions

• Structural Inheritance: – Non-Virtual Functions

207

4. Proper Inheritance

Three Kinds of Inheritance There are three kinds of inheritance because there are three kinds of member functions:

• Interface Inheritance: – Pure Virtual Functions

• Structural Inheritance: – Non-Virtual Functions

• Implementation Inheritance: –Non-Pure Virtual Functions

208

4. Proper Inheritance

Interface Inheritance

class TcpChannel : public Channel {

/* … */

public:

// … (creators)

virtual int read(char *buffer, int numBytes) {…}

virtual int write(const char *buffer, int numBytes) {…}

};

class Channel {

public:

virtual ~Channel() { }

virtual int read(char *buffer, int numBytes) = 0;

virtual int write(const char *buffer, int numBytes) = 0;

};

TcpChannel

Channel

209

4. Proper Inheritance

Structural Inheritance

class Pixel : public Point {

public:

enum Color { RED, GREEN, BLUE };

private:

Color d_color;

public:

// … (creators)

void setColor(Color color) { /* … */ }

Color color ( ) const { /* … */ } };

class Point {

int d_x;

int d_y;

public:

// … (creators)

void setX(int x) { /* … */ }

void setY(int y) { /* … */ }

int x() const { /* … */ }

int y() const { /* … */ }

};

Pixel

Point

210

4. Proper Inheritance

Implementation Inheritance

class CompositeWidget : public Widget {

// …

public:

// … (creators)

virtual const char *widgetCategory() const { return "COMP"; }

virtual int numChildren() const { /* … */ }

// …

};

class Widget { Point d_origin;

// …

public:

// … (creators)

virtual bool isNameable() const { return false; }

virtual const char *instanceName() const { return 0; } virtual bool hasLocation() const { return true; }

virtual Point origin() const { return d_origin; }

virtual const char *widgetCategory() const { return "LEAF"; }

virtual int numChildren const { return 0; }

// … };

CompositeWidget

Widget

211

4. Proper Inheritance

What Is Proper Inheritance?

Base

Derived

2

1

Is-Substitutable-For

Is-A

Implements

Extends

212

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship?

– What does it mean?

213

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship?

– What does it mean?

• Weaker Preconditions?

• Stronger Postconditions?

• Same Invariants?

214

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship?

– What does it mean?

• Weaker Preconditions?

• Stronger Postconditions?

• Same Invariants?

• Providing a Proper Superset of Behavior?

215

4. Proper Inheritance

What Is Proper Inheritance? • The “IsA” Relationship?

– What does it mean?

• Weaker Preconditions?

• Stronger Postconditions?

• Same Invariants?

• Providing a Proper Superset of Behavior?

• Substitutability? – Of what?

– What criteria?

216

4. Proper Inheritance

What Is Proper Inheritance?

Base

Derived

2

1

Is-Substitutable-For

Is-A

Implements

Extends

217

4. Proper Inheritance

What Is Proper Inheritance?

Base

Derived

2

1

Is-Substitutable-For

Is-A

Implements

Extends

The Is-A Relation:

The implementation

of a derived class

must satisfy

(simultaneously) its

own contract, as

well as that of

“each” base class.

218

4. Proper Inheritance

What Is Proper Inheritance?

What about the following general property:

For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that base-class pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave!

219

4. Proper Inheritance

What Is Proper Inheritance?

What about the following general property:

For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that base-class pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave!

220

4. Proper Inheritance

What Is Proper Inheritance?

What about the following general property:

For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that base-class pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave!

221

4. Proper Inheritance

What Is Proper Inheritance?

Derived

Base

f(int, double, const char *)

f(int, double, const char *)

222

4. Proper Inheritance

What Is Proper Inheritance?

Derived

Base

f(int, double, const char *)

f(int, double, const char *)

223

4. Proper Inheritance

What Is Proper Inheritance?

Derived

Base

f(int, double, const char *)

f(int, double, const char *)

224

4. Proper Inheritance

What Is Proper Inheritance?

Derived

Base

f(int, double, const char *)

f(int, double, const char *)

225

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived();

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *)

226

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *)

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

227

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *)

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

228

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

229

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

230

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

231

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

232

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

233

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

234

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

bp->f(1, 2.0, “three”);

235

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

dp->f(1, 2.0, “three”);

bp->f(1, 2.0, “three”);

236

4. Proper Inheritance

What Is Proper Inheritance?

Derived *dp = new Derived(); // dp = 0x002140

Base *bp = dp; // bp = 0x002140

Derived

Base

f(int, double, const char *)

f(int, double, const char *) Object of type

Derived

0x002130:

0x002138:

0x002140:

0x002148:

0x002150:

0x002158:

0x002160:

0x002168:

0x002170:

dp->f(1, 2.0, “three”);

bp->f(1, 2.0, “three”); Identical

Behavior

237

4. Proper Inheritance

What Is Proper Inheritance?

What about the following general property:

For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that base-class pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave!

238

4. Proper Inheritance

What Is Proper Inheritance?

What about the following general property:

For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that base-class pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave!

239

4. Proper Inheritance

What Is Proper Inheritance?

Derived Interface

and Contract

Base Interface

and Contract

Derived

Base

h()

g(int)

g(int)

f(int)

f(int)

Base::g(int x); // Defined only for 0 <= x.

Derived::g(int x); // Defined for all x.

Base::f(int x); // Defined for all x.

Derived::f(int x); // Defined for all x.

Derived::h(); // Note: not accessible from Base class.

240

4. Proper Inheritance

What Is Proper Inheritance?

Derived Interface

and Contract

Base Interface

and Contract

Derived

Base

h()

g(int)

g(int)

f(int)

f(int)

Base::g(int x); // Defined only for 0 <= x.

Derived::g(int x); // Defined for all x.

Base::f(int x); // Defined for all x.

Derived::f(int x); // Defined for all x.

Derived::h(); // Note: not accessible from Base class.

241

4. Proper Inheritance

What Is Proper Inheritance?

Derived Interface

and Contract

Base Interface

and Contract

Derived

Base

h()

g(int)

g(int)

f(int)

f(int)

Base::g(int x); // Defined only for 0 <= x.

Derived::g(int x); // Defined for all x.

Base::f(int x); // Defined for all x.

Derived::f(int x); // Defined for all x.

Derived::h(); // Note: not accessible from Base class.

242

4. Proper Inheritance

What Is Proper Inheritance?

Derived Interface

and Contract

Base Interface

and Contract

Derived

Base

h()

g(int)

g(int)

f(int)

f(int)

Base::g(int x); // Defined only for 0 <= x.

Derived::g(int x); // Defined for all x.

Base::f(int x); // Defined for all x.

Derived::f(int x); // Defined for all x.

Derived::h(); // Note: not accessible from Base class.

4. Proper Inheritance

Pure Interface Inheritance

243

For each function D::f in the derived class overriding

a virtual one B::f in the base class, the (documented)

preconditions of D::f must be no stronger than

those for B::f, and the postconditions no weaker.

Derived

Base

Implementation

Interface

Constructors D::f

B::f

4. Proper Inheritance

Pure Interface Inheritance

244

For each function D::f in the derived class overriding

a virtual one B::f in the base class, the (documented)

preconditions of D::f must be no stronger than

those for B::f, and the postconditions no weaker.

Derived

Base

Implementation

Interface

Constructors D::f

B::f

Implements the Interface

4. Proper Inheritance

Pure Interface Inheritance

245

For each function D::f in the derived class overriding

a virtual one B::f in the base class, the (documented)

preconditions of D::f must be no stronger than

those for B::f, and the postconditions no weaker.

Derived

Base

Implementation

Interface

Constructors D::f

B::f

Implements the Interface

4. Proper Inheritance

Pure Interface Inheritance

246

For each function D::f in the derived class overriding

a virtual one B::f in the base class, the (documented)

preconditions of D::f must be no stronger than

those for B::f, and the postconditions no weaker.

Derived

Base

Implementation

Interface

Constructors D::f

B::f

Implements the Interface

are typically the same as

247

4. Proper Inheritance

Pure Interface Inheritance

Channel

B::f

248

4. Proper Inheritance

Pure Interface Inheritance

Channel

B::f

virtual int write(const char *buffer, int numBytes) = 0;

// Write the specified 'numBytes' from the specified

// 'buffer'. Return 0 on success, and a non-zero value

// otherwise. The behavior is undefined unless

// '0 <= numBytes <= 32767'.

249

4. Proper Inheritance

Pure Interface Inheritance

TcpChannel

Channel

D::f

B::f

virtual int write(const char *buffer, int numBytes) = 0;

// Write the specified 'numBytes' from the specified

// 'buffer'. Return 0 on success, and a non-zero value

// otherwise. The behavior is undefined unless

// '0 <= numBytes <= 32767'.

250

4. Proper Inheritance

Pure Interface Inheritance

TcpChannel

Channel

D::f

B::f

virtual int write(const char *buffer, int numBytes);

// Write to this TCP/IP channel the specified

// 'numBytes' from the specified 'buffer'. Return 0 on

// success, and a non-zero value otherwise. The

// behavior is undefined unless '0 == numBytes % 4'.

virtual int write(const char *buffer, int numBytes) = 0;

// Write the specified 'numBytes' from the specified

// 'buffer'. Return 0 on success, and a non-zero value

// otherwise. The behavior is undefined unless

// '0 <= numBytes <= 32767'.

251

4. Proper Inheritance

Pure Interface Inheritance

TcpChannel

Channel

D::f

B::f

virtual int write(const char *buffer, int numBytes);

// Write to this TCP/IP channel the specified

// 'numBytes' from the specified 'buffer'. Return 0 on

// success, 1 if '0 != numBytes % 4', and a negative

// value otherwise.

virtual int write(const char *buffer, int numBytes) = 0;

// Write the specified 'numBytes' from the specified

// 'buffer'. Return 0 on success, and a non-zero value

// otherwise. The behavior is undefined unless

// '0 <= numBytes <= 32767'.

252

4. Proper Inheritance

Pure Interface Inheritance

TcpChannel

Channel

D::f

B::f

virtual int write(const char *buffer, int numBytes);

// Write to this TCP/IP channel the specified

// 'numBytes' from the specified 'buffer'. Return 0 on

// success, and a non-zero value otherwise. Note that

// this functionality is not yet implemented on Windows;

// on that platform, this function always returns -1.

virtual int write(const char *buffer, int numBytes) = 0;

// Write the specified 'numBytes' from the specified

// 'buffer'. Return 0 on success, and a non-zero value

// otherwise. The behavior is undefined unless

// '0 <= numBytes <= 32767'.

253

4. Proper Inheritance

What Is a Proper Subtype/Subclass?

254

4. Proper Inheritance

What Is a Proper Subtype/Subclass?

“A type hierarchy is composed of subtypes and supertypes. The intuitive

idea of a subtype is one whose objects provide all the behavior of objects

of another type (the supertype) plus something extra.” – Barbara Liskov . (OOPSLA ’87)

255

4. Proper Inheritance

What Is a Proper Subtype/Subclass?

“A type hierarchy is composed of subtypes and supertypes. The intuitive

idea of a subtype is one whose objects provide all the behavior of objects

of another type (the supertype) plus something extra.” – Barbara Liskov . (OOPSLA ’87)

TcpChannel

Channel

Interface Inheritance

Can create it.

256

4. Proper Inheritance

What Is a Proper Subtype/Subclass?

“A type hierarchy is composed of subtypes and supertypes. The intuitive

idea of a subtype is one whose objects provide all the behavior of objects

of another type (the supertype) plus something extra.” – Barbara Liskov . (OOPSLA ’87)

Pixel

Point

TcpChannel

Channel

Interface Inheritance

Structural Inheritance

Can create it. Can do something

more with it.

257

4. Proper Inheritance

What Is a Proper Subtype/Subclass?

“A type hierarchy is composed of subtypes and supertypes. The intuitive

idea of a subtype is one whose objects provide all the behavior of objects

of another type (the supertype) plus something extra.” – Barbara Liskov . (OOPSLA ’87)

Pixel

Point

TcpChannel

Channel

CompositeWidget

Widget

Interface Inheritance

Structural Inheritance

Implementation Inheritance

Can create it. Can do something

more with it.

Can create something

else with it.

4. Proper Inheritance

What Is Liskov Substitution?

258

4. Proper Inheritance

What Is Liskov Substitution?

What exactly is the Liskov Substitution Principle (LSP)?

259

4. Proper Inheritance

What Is Liskov Substitution?

What exactly is the Liskov Substitution Principle (LSP)?

• What motivated LSP in the first place?

260

4. Proper Inheritance

What Is Liskov Substitution?

What exactly is the Liskov Substitution Principle (LSP)?

• What motivated LSP in the first place?

• (How?) Does LSP relate to inheritance in C++?

261

4. Proper Inheritance

What Is Liskov Substitution?

What exactly is the Liskov Substitution Principle (LSP)?

• What motivated LSP in the first place?

• (How?) Does LSP relate to inheritance in C++?

• After Liskov substitution is applied, can (observable) behavior be (subtly) different?

262

4. Proper Inheritance

What Is Liskov Substitution?

What exactly is the Liskov Substitution Principle (LSP)?

• What motivated LSP in the first place?

• (How?) Does LSP relate to inheritance in C++?

• After Liskov substitution is applied, can (observable) behavior be (subtly) different?

• Does LSP apply to all three kinds of inheritance?

263

4. Proper Inheritance

What Is Liskov Substitution?

What exactly is the Liskov Substitution Principle (LSP)?

• What motivated LSP in the first place?

• (How?) Does LSP relate to inheritance in C++?

• After Liskov substitution is applied, can (observable) behavior be (subtly) different?

• Does LSP apply to all three kinds of inheritance?

• Does LSP have any other practical applications?

264

4. Proper Inheritance

What Is Liskov Substitution?

What exactly is the Liskov Substitution Principle (LSP)?

• What motivated LSP in the first place?

• (How?) Does LSP relate to inheritance in C++?

• After Liskov substitution is applied, can (observable) behavior be (subtly) different?

• Does LSP apply to all three kinds of inheritance?

• Does LSP have any other practical applications?

• Let’s have a look…

265

266

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

267

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

268

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

269

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

270

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

271

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

272

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

void p(const Bool& x, const Bool& y, …) { /* … */ }

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

273

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

void p(const Bool& x, const Bool& y, …) { /* … */ }

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

Note order is different!

274

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

void p(const Bool& x, const Bool& y, …) { /* … */ }

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

275

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

void p(const Bool& x, const Bool& y, …) { /* … */ }

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

Note order is different!

276

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

277

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

278

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

If, for each “derived-class” object o1 of type S, there exists a “base-class”

object o2 of type T such that, for all programs P defined in terms of type T,

the behavior of P is unchanged when the “derived-class” object o1 is

substituted for the “base-class” object o2, then S is a subtype of T.

279

4. Proper Inheritance

What Is Liskov Substitution?

If, for each “derived-class” object d of type D, there exists a “base-class”

object b of type B such that, for all programs P defined in terms of type B,

the behavior of P is unchanged when the “derived-class” object d is

substituted for the “base-class” object b, then D is a subtype of B.

If, for each “derived-class” object o1 of type S, there exists a “base-class”

object o2 of type T such that, for all programs P defined in terms of type T,

the behavior of P is unchanged when the “derived-class” object o1 is

substituted for the “base-class” object o2, then S is a subtype of T.

“If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

280

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

If, for each “derived-class” object o1 of type S, there exists a “base-class”

object o2 of type T such that, for all programs P defined in terms of type T,

the behavior of P is unchanged when the “derived-class” object o1 is

substituted for the “base-class” object o2, then S is a subtype of T.

If, for each “derived-class” object d of type D, there exists a “base-class”

object b of type B such that, for all programs P defined in terms of type B,

the behavior of P is unchanged when the “derived-class” object d is

substituted for the “base-class” object b, then D is a subtype of B.

If, for each object d of type D, there exists an object b of type B such that,

for all programs P defined in terms of B, the behavior of P is unchanged

when d is substituted for b, then D is a subtype of B.

281

4. Proper Inheritance

What Is Liskov Substitution? “If for each object o1 of type S there is an object o2 of type T such that for

all programs P defined in terms of T, the behavior of P is unchanged when

o1 is substituted for o2, then S is a subtype of T.” – Barbara Liskov (OOPSLA ’87)

If, for each “derived-class” object o1 of type S, there exists a “base-class”

object o2 of type T such that, for all programs P defined in terms of type T,

the behavior of P is unchanged when the “derived-class” object o1 is

substituted for the “base-class” object o2, then S is a subtype of T.

If, for each “derived-class” object d of type D, there exists a “base-class”

object b of type B such that, for all programs P defined in terms of type B,

the behavior of P is unchanged when the “derived-class” object d is

substituted for the “base-class” object b, then D is a subtype of B.

If, for each object d of type D, there exists an object b of type B such that,

for all programs P defined in terms of B, the behavior of P is unchanged

when d is substituted for b, then D is a subtype of B.

282

4. Proper Inheritance

What Is Liskov Substitution?

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

void p(const Bool& x, const Bool& y, …) { /* … */ }

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

If, for each object d of type D, there exists an object b of type B such that,

for all programs P defined in terms of B, the behavior of P is unchanged

when d is substituted for b, then D is a subtype of B.

283

4. Proper Inheritance

What Is Liskov Substitution?

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

void p(const Bool& x, const Bool& y, …) { /* … */ }

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

If, for each object d of type D, there exists an object b of type B such that,

for all programs P defined in terms of B, the behavior of P is unchanged

when d is substituted for b, then D is a subtype of B.

284

4. Proper Inheritance

What Is Liskov Substitution?

class Bool {

bool d_v; public: Bool(int x) : d_v(x) { } operator bool() const {return d_v;} };

class Fool : public Bool {

public: Fool(int x) : Bool(!x) { } };

main()

{ Bool b0(false);

Bool b1(true);

// …

p(b0, b1, …);

}

void p(const Bool& x, const Bool& y, …) { /* … */ }

main()

{ Fool f0(false);

Fool f1(true);

// …

p(f1, f0, …);

}

If, for each object d of type D, there exists an object b of type B such that,

for all programs P defined in terms of B, the behavior of P is unchanged

when d is substituted for b, then D is a subtype of B.

285

4. Proper Inheritance

What Is Proper Inheritance?

Recall the following general property:

For inheritance to be proper, any operation that can be invoked on a derived-class object via a base-class pointer (or reference) must behave identically if we replace that base-class pointer (or reference) with a corresponding derived-class one.

Note that this is how virtual functions behave!

286

4. Proper Inheritance

What Is Proper Inheritance?

void example(Derived *pDerived)

{

Base *pBase = pDerived;

#ifdef USE_DERIVED_CLASS_INTERFACE

pDerived->someMethod(/* … */);

int result = someFunction(*pDerive);

#else

pBase->someMethod(/* … */);

int result = someFunction(*pBase);

#endif

Derived

Base

287

4. Proper Inheritance

Pure Structural Inheritance #ifdef USE_BASE_CLASS_INTERFACE

typedef Point Type;

#else

typedef Pixel Type;

#endif

void anyProgram(Type *p);

void main()

{

Pixel pixel(1, 2, Pixel::BLUE);

anyProgram(&pixel);

}

using std::cout; // (We do this only

using std::endl; // in test drivers.)

Pixel

Point

288

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

cout << p->x() << endl;

}

int Point::x() const

{

return d_x;

}

289

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

p->setY(10);

}

void Point::setY(int y)

{

d_y = y;

}

290

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

cout << p->color() << endl;

}

Pixel::Color Pixel::color() const

{

return d_color;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

291

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

p->setY(10);

}

void Pixel::setY(int y)

{

cout << "Pixel::setY(int y)" << endl;

d_y = y;

}

void Point::setY(int y)

{

d_y = y;

}

292

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

p->setY(10);

}

void Pixel::setY(int y)

{

cout << "Pixel::setY(int y)" << endl;

d_y = y;

}

void Point::setY(int y)

{

d_y = y;

}

!

293

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

p->setY(10);

}

void Pixel::setY(int y)

{

++s_numSetY; // Pixel class data

d_y = y;

}

void Point::setY(int y)

{

d_y = y;

}

class Pixel : public Point {

// …

static int s_numSetY;

public:

// …

};

294

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

p->setY(10);

cout << p->numSetY() << endl;

}

void Pixel::setY(int y)

{

++s_numSetY; // Pixel class data

d_y = y;

}

int Pixel::numSetY() { return s_numSetY; }

void Point::setY(int y)

{

d_y = y;

}

class Pixel : public Point {

// …

static int s_numSetY;

public:

// …

};

295

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

p->setY(10);

}

void Pixel::setY(int y)

// Set the y-coordinate of this object to the absolute value of the

// specified 'y'. The behavior is undefined unless 'INT_MIN < y'.

{

d_y = y < 0 ? -y : y;

}

void Point::setY(int y)

// Set the y-coordinate of this object to the specified 'y'.

// The behavior is undefined unless '0 <= y'.

{

d_y = y;

}

296

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof p->self() > sizeof(Point))

cout << "It's not a Point!" << endl;

}

const Pixel& Pixel::self() const

{

return *this;

}

const Point& Point::self() const

{

return *this;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

297

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof p->self() > sizeof(Point)) ?

cout << "It's not a Point!" << endl;

}

const Pixel& Pixel::self() const

{

return *this;

}

const Point& Point::self() const

{

return *this;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

298

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof p->self() > 8) // sizeof(Point)

cout << "It's not a Point!" << endl;

}

const Pixel& Pixel::self() const

{

return *this;

}

const Point& Point::self() const

{

return *this;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

299

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof p->self() > 8) // sizeof(Point)

cout << "It's not a Point!" << endl;

}

const Pixel& Pixel::self() const

{

return *this;

}

const Point& Point::self() const

{

return *this;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

300

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof p->self() > 8) // sizeof(Point)

cout << "It's not a point!" << endl;

}

const Pixel& Pixel::self() const

{

return *this;

}

const Point& Point::self() const

{

return *this;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

301

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof p->self() > sizeof(Point))

cout << "It's not a Point!" << endl;

}

const Pixel& Pixel::self() const

{

return *this;

}

const Point& Point::self() const

{

return *this;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

302

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof p->self() > sizeof(Point))

cout << "It's not a Point!" << endl;

}

const Pixel& Pixel::self() const

{

return *this;

}

const Point& Point::self() const

{

return *this;

}

!

class Pixel : public Point {

// …

Color d_color;

// …

};

303

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof *p > sizeof(Point))

cout << "It's not a Point!" << endl;

}

class Pixel : public Point {

// …

Color d_color;

// …

};

304

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof *p > sizeof(Point))

cout << "It's not a Point!" << endl;

}

class Pixel : public Point {

// …

Color d_color;

// …

}; !

305

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof *p > sizeof(Point))

cout << "It's not a Point!" << endl;

}

class Pixel : public Point {

// …

Color d_color;

// …

}; !

306

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

if (sizeof *p > sizeof(Point))

cout << "It's not a Point!" << endl;

}

class Pixel : public Point {

// …

Color d_color;

// …

}; !

Proper Structural

Inheritance extends

functionality, but

does not extend the

object’s footprint.

307

4. Proper Inheritance

Pure Structural Inheritance

Pixel

Point

void anyProgram(Type *p)

{

double alignmentHack; // Don’t do it!

char buffer[sizeof(Point)];

(Type *)&buffer = *p;

}

class Pixel : public Point {

// …

Color d_color;

// …

}; !

buffer

buffer

The same “size” issue applies to arrays of objects!

?!?!

308

4. Proper Inheritance

Implementation Inheritance

CompositeWidget

Widget

Implementation hierarchies

are highly problematic!

Incorporating implementation with interface

inheritance: – Makes software brittle, inflexible, and hard to

maintain.

– Exposes public clients to physical (compile-

and link-time) dependencies on the shared

implementation.

– Adds nothing that cannot be done with pure

interface inheritance and layering.

Its only value is as a syntactic expedient!

4. Proper Inheritance

Using Interface Inheritance Effectively

309

Point

Polygon Square

Rectangle

Shape

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

310

Point

Polygon Square

Rectangle

Shape

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

x; y

4. Proper Inheritance

Using Interface Inheritance Effectively

311

Point

Polygon Square

Rectangle

Shape

x; y

origin; width

origin; width; length

origin

?

A Rectangle

Is-A Square

with a length

attribute?

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

312

Point

Polygon Square

Rectangle

Shape

x; y

origin; width

origin; width; length

origin

?

A Rectangle

Is-A Square

with a length

attribute?

origin; numVertices;

operator[](int index)

MyRectangle

Rectangle does not respect

Square

Invariant

4. Proper Inheritance

Using Interface Inheritance Effectively

313

Point

Polygon Square

Rectangle

Shape

x; y

origin; width

origin; width; length

origin

?

A Rectangle

Is-A Square

with a length

attribute?

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

314

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

315

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

316

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

317

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

318

Square

Rectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

319

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

4. Proper Inheritance

Using Interface Inheritance Effectively

320

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

4. Proper Inheritance

Using Interface Inheritance Effectively

321

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

4. Proper Inheritance

Using Interface Inheritance Effectively

322

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

4. Proper Inheritance

Using Interface Inheritance Effectively

323

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

4. Proper Inheritance

Using Interface Inheritance Effectively

324

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

4. Proper Inheritance

Using Interface Inheritance Effectively

325

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

4. Proper Inheritance

Using Interface Inheritance Effectively

326

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

Either Assert

or No Longer

Square

4. Proper Inheritance

Using Interface Inheritance Effectively

327

Square

Rectangle void stretchBy1(Rectangle *r)

{

int wid = r->width();

int len = r->length();

r->setLength(len + 1);

assert(wid == r->width());

assert(len + 1 == r->length());

}

Either Assert

or No Longer

Square

4. Proper Inheritance

Using Interface Inheritance Effectively

328

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

329

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

330

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

331

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

332

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

333

Point

Polygon Square

Shape

Rectangle

x; y

origin; width

origin; width; length

origin

origin; numVertices;

operator[](int index)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

334 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

335 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

336 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

337 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

338 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

339 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

340 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

341 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

342 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

343 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

344 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

345 origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

(Concrete)

MyRectangle

4. Proper Inheritance

Using Interface Inheritance Effectively

346

(Concrete)

MyRectangle

origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

4. Proper Inheritance

Using Interface Inheritance Effectively

347

(Concrete)

MyRectangle

origin() const;

(Modifiable) Rectangle

ConstShape

(Modifiable) Square

(Modifiable) Polygon

(Modifiable) Shape

(Concrete)

YourSquare (Concrete)

TheirPolygon

ConstRectangle

ConstPolygon

ConstSquare int side() const

int width() const

int length() const

Point vertex(int i) const

int numVertices() const

void setOrigin(const Point& v);

void setSide(int side)

void setWidth(int width)

void setLength(int length)

void appendVertex(const Point& v)

void removeVertex(int i)

TheirPolygon() YourSquare() MyRectangle()

The principal clients of Interface Inheritance

are both the

PUBLIC CLIENT

and the

DERIVED-CLASS AUTHOR.

4. Proper Inheritance

Using Interface Inheritance Effectively

348

4. Proper Inheritance

Using Interface Inheritance Effectively

349

Channel

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

350

Channel

MyChannel

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

351

Channel

MyChannel

Client1

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

352

Channel

TimedChannel

MyChannel

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

353

Channel

TimedChannel

MyChannel

YourTimedChannel

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

354

Channel

TimedChannel

MyChannel

YourTimedChannel

Client2

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

355

Channel

TimedChannel

3rd Party

Product A

MyChannel

YourTimedChannel

Client2

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

356

Channel

TimedChannel

3rd Party

Product A

PaChannelAdapter

MyChannel

YourTimedChannel

Client2

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

357

Channel

TimedChannel

3rd Party

Product A

PaChannelAdapter

MyChannel

YourTimedChannel

Client2

Client3

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

358

Channel

TimedChannel

3rd Party

Product A

3rd Party

Product B

PaChannelAdapter

MyChannel

YourTimedChannel

Client2

Client3

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

359

Channel

TimedChannel

3rd Party

Product A

3rd Party

Product B

PaChannelAdapter

PbTimedChannelAdapter

MyChannel

YourTimedChannel

Client2

Client3

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

360

Channel

TimedChannel

3rd Party

Product A

3rd Party

Product B

PaChannelAdapter

PbTimedChannelAdapter

MyChannel

YourTimedChannel Client4

Client2

Client3

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Interface Inheritance Effectively

361

Channel

TimedChannel

3rd Party

Product A

3rd Party

Product B

PaChannelAdapter

PbTimedChannelAdapter

MyChannel

YourTimedChannel Client4

Client2

Client5

Client3

Client1

int write(const char *b, int n, int t);

int read(char *b, int n, int t);

int write(const char *b, int n);

int read(char *b, int n);

4. Proper Inheritance

Using Structural Inheritance Effectively

362

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

4. Proper Inheritance

Using Structural Inheritance Effectively

363

(Non-Modifiable)

ConstElemRef

template <class TYPE>

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

friend class ElemRef<TYPE>; // Note friendship

private: // Not Implemented. TBD

ConstElemRef& operator=(Const ConstElemRef&);

public:

// CREATORS

ConstElemRef(const TYPE *elem);

ConstElemRef(const ConstElemRef& ref);

~ConstElemRef();

// ACCESSORS

const TYPE& elem() const;

};

elem() ;

4. Proper Inheritance

Using Structural Inheritance Effectively

364

(Non-Modifiable)

ConstElemRef

template <class TYPE>

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

friend class ElemRef<TYPE>; // Note friendship

private: // Not Implemented. TBD

ConstElemRef& operator=(Const ConstElemRef&);

public:

// CREATORS

ConstElemRef(const TYPE *elem);

ConstElemRef(const ConstElemRef& ref);

~ConstElemRef();

// ACCESSORS

const TYPE& elem() const;

};

elem() ;

Single Pointer Data Member

4. Proper Inheritance

Using Structural Inheritance Effectively

365

(Non-Modifiable)

ConstElemRef

template <class TYPE>

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

friend class ElemRef<TYPE>; // Note friendship

private: // Not Implemented. TBD

ConstElemRef& operator=(Const ConstElemRef&);

public:

// CREATORS

ConstElemRef(const TYPE *elem);

ConstElemRef(const ConstElemRef& ref);

~ConstElemRef();

// ACCESSORS

const TYPE& elem() const;

};

elem() ;

Derived Class Declared Friend

4. Proper Inheritance

Using Structural Inheritance Effectively

366

(Non-Modifiable)

ConstElemRef

template <class TYPE>

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

friend class ElemRef<TYPE>; // Note friendship

private: // Not Implemented. TBD

ConstElemRef& operator=(Const ConstElemRef&);

public:

// CREATORS

ConstElemRef(const TYPE *elem);

ConstElemRef(const ConstElemRef& ref);

~ConstElemRef();

// ACCESSORS

const TYPE& elem() const;

};

elem() ;

Copy Assignment Not Implemented

4. Proper Inheritance

Using Structural Inheritance Effectively

367

(Non-Modifiable)

ConstElemRef

template <class TYPE>

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

friend class ElemRef<TYPE>; // Note friendship

private: // Not Implemented. TBD

ConstElemRef& operator=(Const ConstElemRef&);

public:

// CREATORS

ConstElemRef(const TYPE *elem);

ConstElemRef(const ConstElemRef& ref);

~ConstElemRef();

// ACCESSORS

const TYPE& elem() const;

};

elem() ;

Read-Only Access

4. Proper Inheritance

Using Structural Inheritance Effectively

368

ConstElemRef

template <class TYPE>

class ElemRef<TYPE> : public ConstElemRef<TYPE> {

public:

// CREATORS

ElemRef(TYPE *elem);

ElemRef(const ElemRef& ref);

~ElemRef();

// MANIPULATORS

ElemRef& operator=(const ElemRef&); // Fine. TBD

// ACCESSORS

TYPE& elem() const;

};

(Modifiable)

ElemRef

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

// …

const TYPE& elem() const;

};

elem() ;

elem() ;

4. Proper Inheritance

Using Structural Inheritance Effectively

369

ConstElemRef

template <class TYPE>

class ElemRef<TYPE> : public ConstElemRef<TYPE> {

public:

// CREATORS

ElemRef(TYPE *elem);

ElemRef(const ElemRef& ref);

~ElemRef();

// MANIPULATORS

ElemRef& operator=(const ElemRef&); // Fine. TBD

// ACCESSORS

TYPE& elem() const;

};

(Modifiable)

ElemRef

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

// …

const TYPE& elem() const;

};

elem() ;

elem() ;

Public Structural

Inheritance

4. Proper Inheritance

Using Structural Inheritance Effectively

370

ConstElemRef

template <class TYPE>

class ElemRef<TYPE> : public ConstElemRef<TYPE> {

public:

// CREATORS

ElemRef(TYPE *elem);

ElemRef(const ElemRef& ref);

~ElemRef();

// MANIPULATORS

ElemRef& operator=(const ElemRef&); // Fine. TBD

// ACCESSORS

TYPE& elem() const;

};

(Modifiable)

ElemRef

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

// …

const TYPE& elem() const;

};

elem() ;

elem() ;

No Additional Member Data

4. Proper Inheritance

Using Structural Inheritance Effectively

371

ConstElemRef

template <class TYPE>

class ElemRef<TYPE> : public ConstElemRef<TYPE> {

public:

// CREATORS

ElemRef(TYPE *elem);

ElemRef(const ElemRef& ref);

~ElemRef();

// MANIPULATORS

ElemRef& operator=(const ElemRef&); // Fine. TBD

// ACCESSORS

TYPE& elem() const;

};

(Modifiable)

ElemRef

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

// …

const TYPE& elem() const;

};

elem() ;

elem() ;

Copy Assignment Implemented

4. Proper Inheritance

Using Structural Inheritance Effectively

372

ConstElemRef

template <class TYPE>

class ElemRef<TYPE> : public ConstElemRef<TYPE> {

public:

// CREATORS

ElemRef(TYPE *elem);

ElemRef(const ElemRef& ref);

~ElemRef();

// MANIPULATORS

ElemRef& operator=(const ElemRef&); // Fine. TBD

// ACCESSORS

TYPE& elem() const;

};

(Modifiable)

ElemRef

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

// …

const TYPE& elem() const;

};

elem() ;

elem() ;

Read-Write Access

4. Proper Inheritance

Using Structural Inheritance Effectively

373

ConstElemRef

template <class TYPE>

class ElemRef<TYPE> : public ConstElemRef<TYPE> {

public:

// CREATORS

ElemRef(TYPE *elem);

ElemRef(const ElemRef& ref);

~ElemRef();

// MANIPULATORS

ElemRef& operator=(const ElemRef&); // Fine. TBD

// ACCESSORS

TYPE& elem() const;

};

(Modifiable)

ElemRef

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

// …

const TYPE& elem() const;

};

elem() ;

elem() ;

Read-Write Access

An ElemRef

Is-A ConstElemRef

with “Write Access”

4. Proper Inheritance

Using Structural Inheritance Effectively

374

ConstElemRef

template <class TYPE>

class ElemRef<TYPE> : public ConstElemRef<TYPE> {

public:

// CREATORS

ElemRef(TYPE *elem);

ElemRef(const ElemRef& ref);

~ElemRef();

// MANIPULATORS

ElemRef& operator=(const ElemRef&); // Fine. TBD

// ACCESSORS

TYPE& elem() const;

};

(Modifiable)

ElemRef

class ConstElemRef<TYPE> {

const TYPE *d_elem_p;

// …

const TYPE& elem() const;

};

elem() ;

elem() ;

Read-Write Access

An std::iterator

Is-A std::const_iterator

with “Write Access”

4. Proper Inheritance

Using Structural Inheritance Effectively

375

const TYPE& ConstElemRef::elem() const

{

return *d_elem_p;

}

TYPE& ElemRef::elem() const

{

return *const_cast<TYPE *>(d_elem_p);

}

// Note use of friendship as well.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Note: same component due to friendship.

4. Proper Inheritance

Using Structural Inheritance Effectively

376

const TYPE& ConstElemRef::elem() const

{

return *d_elem_p;

}

TYPE& ElemRef::elem() const

{

return *const_cast<TYPE *>(d_elem_p);

}

// Note use of friendship as well.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Note: same component due to friendship.

Note we are casting-away const

4. Proper Inheritance

Using Structural Inheritance Effectively

377

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

4. Proper Inheritance

Using Structural Inheritance Effectively

378

void g(ConstElemRef *cer1, const ConstElemRef& cer2)

{ *cer1 = cer2; // Enable const-correctness violation due to slicing.

} // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

template < class TYPE>

void f(const TYPE& constElem)

{

TYPE dummy;

ElemRef er(&dummy);

ConstElemRef cer(&constElem);

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'.

er.elem() = TYPE(); // Clobber 'constElem'.

4. Proper Inheritance

Using Structural Inheritance Effectively

379

void g(ConstElemRef *cer1, const ConstElemRef& cer2)

{ *cer1 = cer2; // Enable const-correctness violation due to slicing.

} // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

template < class TYPE>

void f(const TYPE& constElem)

{

TYPE dummy;

ElemRef er(&dummy);

ConstElemRef cer(&constElem);

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'.

er.elem() = TYPE(); // Clobber 'constElem'.

4. Proper Inheritance

Using Structural Inheritance Effectively

380

void g(ConstElemRef *cer1, const ConstElemRef& cer2)

{ *cer1 = cer2; // Enable const-correctness violation due to slicing.

} // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

template < class TYPE>

void f(const TYPE& constElem)

{

TYPE dummy;

ElemRef er(&dummy);

ConstElemRef cer(&constElem);

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'.

er.elem() = TYPE(); // Clobber 'constElem'.

4. Proper Inheritance

Using Structural Inheritance Effectively

381

void g(ConstElemRef *cer1, const ConstElemRef& cer2)

{ *cer1 = cer2; // Enable const-correctness violation due to slicing.

} // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

template < class TYPE>

void f(const TYPE& constElem)

{

TYPE dummy;

ElemRef er(&dummy);

ConstElemRef cer(&constElem);

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'.

er.elem() = TYPE(); // Clobber 'constElem'.

4. Proper Inheritance

Using Structural Inheritance Effectively

382

void g(ConstElemRef *cer1, const ConstElemRef& cer2)

{ *cer1 = cer2; // Enable const-correctness violation due to slicing.

} // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

template < class TYPE>

void f(const TYPE& constElem)

{

TYPE dummy;

ElemRef er(&dummy);

ConstElemRef cer(&constElem);

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'.

er.elem() = TYPE(); // Clobber 'constElem'.

4. Proper Inheritance

Using Structural Inheritance Effectively

383

void g(ConstElemRef *cer1, const ConstElemRef& cer2)

{ *cer1 = cer2; // Enable const-correctness violation due to slicing.

} // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

template < class TYPE>

void f(const TYPE& constElem)

{

TYPE dummy;

ElemRef er(&dummy);

ConstElemRef cer(&constElem);

g(&er, cer); // Rebind (modifiable) 'ElemRef' 'er'.

er.elem() = TYPE(); // Clobber 'constElem'.

4. Proper Inheritance

Using Structural Inheritance Effectively

384

void g(ConstElemRef *cer1, const ConstElemRef& cer2)

{ *cer1 = cer2; // Enable const-correctness violation due to slicing.

} // Assumes copy assignment is enabled on the ConstElemRef base class.

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

Be especially careful to ensure const-correctness when const-casting is involved.

4. Proper Inheritance

Using Structural Inheritance Effectively

385

The principal client of Structural Inheritance

is the

PUBLIC CLIENT.

4. Proper Inheritance

Using Structural Inheritance Effectively

386

ConstElemRefClient

(Non-Modifiable)

ConstElemRef

(Modifiable)

ElemRef

ElemRefClient

Note: No Runtime-Performance

Overhead (e.g., due to Dynamic

Binding).

4. Proper Inheritance

Using Implementation Inheritance Effectively

387

CompositeWidget

Widget

instanceName origin move draw numChildren addChild removeChild

WidgetClient

4. Proper Inheritance

Using Implementation Inheritance Effectively

388

CompositeWidget

Widget

instanceName origin move draw

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

4. Proper Inheritance

Using Implementation Inheritance Effectively

389

CompositeWidget

Widget

instanceName origin move draw

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

MyWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

390

CompositeWidget

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

391

CompositeWidget

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

392

CompositeWidget

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

MyCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

4. Proper Inheritance

Using Implementation Inheritance Effectively

393

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

394

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

395

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

396

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

397

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

398

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

399

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

400

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

4. Proper Inheritance

Using Implementation Inheritance Effectively

401

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

Widen interface

first;

4. Proper Inheritance

Using Implementation Inheritance Effectively

402

WidgetImp

numChildren addChild removeChild

WidgetClient

CompositeWidgetClient

instanceName origin move draw

Widget

MyWidget

YourWidget

CompositeWidget

CompositeWidgetImp

MyCompositeWidget

YourCompositeWidget

Widen interface

first; then provide

implementation

without widening.

4. Proper Inheritance

Using Implementation Inheritance Effectively

403

The principal client of Implementation Inheritance

is the

DERIVED-CLASS AUTHOR.

4. Proper Inheritance

Using Implementation Inheritance Effectively

404

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

405 Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

406 Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

407

WidgetPartialImp

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

408

WidgetPartialImp

CompositeWidgetPartialImp

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

409

WidgetPartialImp

CompositeWidgetPartialImp

MyWidget

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

410

WidgetPartialImp

CompositeWidgetPartialImp

MyCompositeWidget

MyWidget

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

411

WidgetPartialImp

CompositeWidgetPartialImp

MyCompositeWidget YourWidget

MyWidget

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

412

WidgetPartialImp

CompositeWidgetPartialImp

YourCompositeWidget

MyCompositeWidget YourWidget

MyWidget

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

413

WidgetPartialImp

CompositeWidgetPartialImp

YourCompositeWidget

MyCompositeWidget YourWidget

TheirCompositeWidget MyWidget

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

4. Proper Inheritance

Using Implementation Inheritance Effectively

414

WidgetPartialImp

CompositeWidgetPartialImp

YourCompositeWidget

MyCompositeWidget YourWidget

TheirCompositeWidget MyWidget

TheirWidget

Framework

Part of Framework using CompositeWidget

Part of Framework using Widget

Widget

CompositeWidget

numChildren addChild removeChild

instanceName origin move draw

415

4. Proper Inheritance

Combining Kinds of Inheritance

416

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface

417

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface

–Typically for Efficiency and Syntactic Sugar.

418

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface

–Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation

419

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface

–Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation –Interface inheritance (widening) first; then

implementation inheritance (no widening) .

420

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface

–Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation –Interface inheritance (widening) first; then

implementation inheritance (no widening) .

• Implementation & Structural

421

4. Proper Inheritance

Combining Kinds of Inheritance • Structural & Interface

–Typically for Efficiency and Syntactic Sugar.

• Interface & Implementation –Interface inheritance (widening) first; then

implementation inheritance (no widening) .

• Implementation & Structural –Bad Idea: Unnecessarily addresses the

needs of derived class authors and public clients in the same physical component.

422

4. Proper Inheritance

Combining Kinds of Inheritance

inline int f(); virtual void g() = 0; virtual void h() = 0;

Public

Client

virtual void g();

virtual void g() { } virtual void h() { }

423

4. Proper Inheritance

Combining Kinds of Inheritance

inline int f(); virtual void g(); virtual void h();

virtual void g();

Public

Client

424

4. Proper Inheritance

Combining Kinds of Inheritance

inline int f(); virtual void g(); virtual void h();

virtual void g();

Public

Client

425

4. Proper Inheritance

Combining Kinds of Inheritance

inline int f(); virtual void g(); virtual void h();

virtual void g();

Public

Client

426

4. Proper Inheritance

Relative Utility Interface Inheritance

Structural Inheritance

Implementation Inheritance

427

4. Proper Inheritance

Physical Substitutability

428

4. Proper Inheritance

Physical Substitutability

429

4. Proper Inheritance

Physical Substitutability

430

4. Proper Inheritance

Physical Substitutability

What Criteria Must Be Satisfied?

431

4. Proper Inheritance

Physical Substitutability

The new component’s logical behavior:

432

4. Proper Inheritance

Physical Substitutability

The new component’s logical behavior:

• Preconditions needed for defined behavior can be made weaker, but no stronger.

433

4. Proper Inheritance

Physical Substitutability

The new component’s logical behavior:

• Preconditions needed for defined behavior can be made weaker, but no stronger.

• Pre-existing essential behavior of the component must remain unchanged.

434

4. Proper Inheritance

Physical Substitutability

The new component’s logical behavior:

• Preconditions needed for defined behavior can be made weaker, but no stronger.

• Pre-existing essential behavior of the component must remain unchanged.

• New behaviors may be defined, and essential ones extended, so long as the component is backward compatible with pre-existing clients.

435

4. Proper Inheritance

Physical Substitutability

The new component’s physical characteristics:

436

4. Proper Inheritance

Physical Substitutability

The new component’s physical characteristics:

• Physical dependencies cannot increase (much).

437

4. Proper Inheritance

Physical Substitutability

The new component’s physical characteristics:

• Physical dependencies cannot increase (much).

• Compile-time cannot increase substantially.

438

4. Proper Inheritance

Physical Substitutability

The new component’s physical characteristics:

• Physical dependencies cannot increase (much).

• Compile-time cannot increase substantially.

• Size (footprint) cannot increase (much).

439

4. Proper Inheritance

Physical Substitutability

The new component’s physical characteristics:

• Physical dependencies cannot increase (much).

• Compile-time cannot increase substantially.

• Size (footprint) cannot increase (much).

• Dynamic memory usage can’t increase (much).

440

4. Proper Inheritance

Physical Substitutability

The new component’s physical characteristics:

• Physical dependencies cannot increase (much).

• Compile-time cannot increase substantially.

• Size (footprint) cannot increase (much).

• Dynamic memory usage can’t increase (much).

• Can’t introduce dynamic memory allocation.

441

4. Proper Inheritance

Physical Substitutability

The new component’s physical characteristics:

• Physical dependencies cannot increase (much).

• Compile-time cannot increase substantially.

• Size (footprint) cannot increase (much).

• Dynamic memory usage can’t increase (much).

• Can’t introduce dynamic memory allocation.

• Runtime must not be increased significantly for important (relevant) use-cases.

442

4. Proper Inheritance

End of Section

Questions?

443

4. Proper Inheritance

What Questions are we Answering? • What distinguishes Interface, Structural, and

Implementation inheritance?

• What do we mean by the Is-A relationship, & how does proper inheritance vary from one form to the next. – What does LSP (Liskov Substitution Principle) have to do with it?

• How are each of the three inheritances used effectively? – Who is the principal client of each kind of inheritance?

– How are interface and implementation inheritance ordered?

– Does it make sense to combine two (or all three) inheritances?

– What is the relative utility of the three forms of inheritance?

• How are structural inheritance, (logical) substitutability, & backward compatibility of (physical) components related?

444

Outline

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

445

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

Conclusion

446

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

• A Component – a .h/.cpp pair satisfying four essential properties – is our fundamental unit of both logical and physical software design.

Conclusion

447

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

• A Component – a .h/.cpp pair satisfying four essential properties – is our fundamental unit of both logical and physical software design.

• Logical relationships, such as Is-A and Uses between classes, imply physical dependencies among the components that defined them.

Conclusion

448

1. Components (review)

Modularity, Logical/Physical Dependencies, & Level numbers

• A Component – a .h/.cpp pair satisfying four essential properties – is our fundamental unit of both logical and physical software design.

• Logical relationships, such as Is-A and Uses between classes, imply physical dependencies among the components that defined them.

• No cyclic dependencies / long-distance friendships!

Conclusion

449

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

Conclusion

450

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic.

Conclusion

451

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions.

Conclusion

452

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions.

• Undefined Behavior if a precondition isn’t met.

Conclusion

453

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions.

• Undefined Behavior if a precondition isn’t met. • What undefined behavior does is undefined!

Conclusion

454

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions.

• Undefined Behavior if a precondition isn’t met. • What undefined behavior does is undefined! • Documented essential behavior must not change!

Conclusion

455

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions.

• Undefined Behavior if a precondition isn’t met. • What undefined behavior does is undefined! • Documented essential behavior must not change!

• Test drivers must verify all essential behavior.

Conclusion

456

2. Interfaces and Contracts (review)

Syntax versus Semantics & Essential Behavior

• An interface is syntactic; a contract is semantic. • A contract defines both pre- & postconditions.

• Undefined Behavior if a precondition isn’t met. • What undefined behavior does is undefined! • Documented essential behavior must not change!

• Test drivers must verify all essential behavior. • Assertions in destructors help verify invariants.

Conclusion

457

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

Conclusion

458

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

Conclusion

459

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

• Appropriately narrow contracts are GOOD:

Conclusion

460

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

• Appropriately narrow contracts are GOOD:

– Reduce costs associated with development/testing

Conclusion

461

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

• Appropriately narrow contracts are GOOD:

– Reduce costs associated with development/testing

– Improve performance and reduces object-code size

Conclusion

462

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

• Appropriately narrow contracts are GOOD:

– Reduce costs associated with development/testing

– Improve performance and reduces object-code size

– Allow useful behavior to be added as needed

Conclusion

463

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

• Appropriately narrow contracts are GOOD:

– Reduce costs associated with development/testing

– Improve performance and reduces object-code size

– Allow useful behavior to be added as needed

– Enable practical/effective Defensive Programming

Conclusion

464

3. Narrow versus Wide Contracts (review)

The Significance of Undefined Behavior

• Narrow contracts admit undefined behavior.

• Appropriately narrow contracts are GOOD:

– Reduce costs associated with development/testing

– Improve performance and reduces object-code size

– Allow useful behavior to be added as needed

– Enable practical/effective Defensive Programming

• Defensive programming means fault intolerance!

Conclusion

465

Conclusion

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

466

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts.

Conclusion

467

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts.

• The static type of the pointer/reference should make no difference in programmatic behavior.

Conclusion

468

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts.

• The static type of the pointer/reference should make no difference in programmatic behavior.

• Interface inheritance is (virtually :-) all we need!

Conclusion

469

4. Proper Inheritance Is-A for Interface, Structural, & Implementation Inheritance

• The derived class must adhere to both contracts.

• The static type of the pointer/reference should make no difference in programmatic behavior.

• Interface inheritance is (virtually :-) all we need!

• Backward compatibility for components is a whole lot like proper structural inheritance.

Conclusion

470

Conclusion

The End

top related